home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / game / misc / WormWars.lha / WormWars / Source / engine.c < prev    next >
C/C++ Source or Header  |  2001-04-21  |  184KB  |  4,968 lines

  1. /* $Filename: WormWars/Source/engine.c
  2.  * $VER:      WormWars 6.6
  3.  *
  4.  * © Copyright 2001 James R. Jacobs. Freely distributable.
  5.  */
  6.  
  7. #include <string.h>
  8. #include <math.h>
  9. #include <stdio.h>
  10. #include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
  11. #include <assert.h>
  12. #define ASSERT
  13.  
  14. #include "stdafx.h"
  15. #include "diff.h"
  16. #include "same.h"
  17. #include "engine.h"
  18.  
  19. /* PRIVATE STRUCTURES -------------------------------------------------- */
  20.  
  21. struct
  22. {   SBYTE x, y, deltax, deltay;
  23.     ABOOL alive, moved, teleported, visible, reflected;
  24. } bullet[9];
  25. struct
  26. {   UWORD freq;
  27.     ULONG score;
  28. } object[LASTOBJECT + 1] =
  29. {   {1280,  60}, // AFFIXER
  30.     {  60,  20}, // AMMO
  31.     { 110,  20}, // ARMOUR
  32.     {  70,  50}, // BIAS
  33.     { 150,  30}, // BOMB
  34.     {  80,  10}, // BONUS
  35.     {1020,  60}, // CLOCK
  36.     { 380,  50}, // CONVERTER
  37.     { 160,  80}, // CUTTER
  38.     { 250,  90}, // CYCLONE
  39.     { 500,  30}, // FREEDOM
  40.     { 320,  50}, // GROWER
  41.     {1900,  90}, // HEALER
  42.     {1360,  60}, // ICE
  43.     { 140,  60}, // LIFE
  44.     { 160,  80}, // LIGHTNING
  45.     { 970,  80}, // MAGNET
  46.     { 240,  40}, // MISSILE
  47.     { 640,  50}, // MULTIPLIER
  48.     { 400,  10}, // NITRO
  49.     { 240,  30}, // POWER
  50.     { 480,  50}, // PROTECTOR
  51.     { 210,  40}, // PULSE
  52.     { 300,  50}, // PUSHER
  53.     { 400,  40}, // REMNANTS
  54.     { 500,  30}, // SIDESHOT
  55.     { 600,  40}, // SLAYER
  56.     { 980,  40}, // SLOWER
  57.     { 730,  70}, // SWITCHER
  58.     { 320,  20}, // TONGUE
  59.     {1400, 120}, // TREASURE
  60.     {3800, 140}  // UMBRELLA
  61. };
  62.  
  63. /*  -200    common
  64.     220-400 uncommon
  65.     420-980 rare
  66.     1000+   very rare */
  67.  
  68. struct
  69. {   SBYTE x, y, deltax, deltay, relx, rely;
  70.     ABOOL alive, last, visible;
  71. } protector[4][PROTECTORS + 1];
  72. struct
  73. {   SBYTE deltax, deltay;
  74. } thewormqueue[4][WORMQUEUELIMIT + 1];
  75. struct
  76. {   SBYTE deltax, deltay;
  77. } thedogqueue[CREATURES + 1][DOGQUEUELIMIT + 1];
  78. struct
  79. {   ABOOL alive;
  80.     SBYTE x, y, player;
  81.     UBYTE object;
  82. } magnet[MAGNETS + 1];
  83.  
  84. SBYTE eachworm[4][2][9] =
  85. { { { GREENHEADUP,   GREENHEADUP,   GREENHEADUP,
  86.       GREENHEADLEFT, ANYTHING,      GREENHEADRIGHT,
  87.       GREENHEADDOWN, GREENHEADDOWN, GREENHEADDOWN
  88.     },
  89.     { GREENMODEUP,   GREENMODEUP,   GREENMODEUP,
  90.       GREENMODELEFT, ANYTHING,      GREENMODERIGHT,
  91.       GREENMODEDOWN, GREENMODEDOWN, GREENMODEDOWN
  92.   } },
  93.   { { REDHEADUP,     REDHEADUP,     REDHEADUP,
  94.       REDHEADLEFT,   ANYTHING,      REDHEADRIGHT,
  95.       REDHEADDOWN,   REDHEADDOWN,   REDHEADDOWN
  96.     },
  97.     { REDMODEUP,     REDMODEUP,     REDMODEUP,
  98.       REDMODELEFT,   ANYTHING,      REDMODERIGHT,
  99.       REDMODEDOWN,   REDMODEDOWN,   REDMODEDOWN
  100.   } },
  101.   { { BLUEHEADUP,    BLUEHEADUP,    BLUEHEADUP,
  102.       BLUEHEADLEFT,  ANYTHING,      BLUEHEADRIGHT,
  103.       BLUEHEADDOWN,  BLUEHEADDOWN,  BLUEHEADDOWN
  104.     },
  105.     { BLUEMODEUP,    BLUEMODEUP,    BLUEMODEUP,
  106.       BLUEMODELEFT,  ANYTHING,      BLUEMODERIGHT,
  107.       BLUEMODEDOWN,  BLUEMODEDOWN,  BLUEMODEDOWN
  108.   } },
  109.   { { YELLOWHEADUP,  YELLOWHEADUP,  YELLOWHEADUP,
  110.       YELLOWHEADLEFT,ANYTHING,      YELLOWHEADRIGHT,
  111.       YELLOWHEADDOWN,YELLOWHEADDOWN,YELLOWHEADDOWN
  112.     },
  113.     { YELLOWMODEUP,  YELLOWMODEUP,  YELLOWMODEUP,
  114.       YELLOWMODELEFT,ANYTHING,      YELLOWMODERIGHT,
  115.       YELLOWMODEDOWN,YELLOWMODEDOWN,YELLOWMODEDOWN
  116. } } };
  117.  
  118. /* Rules for variable types:
  119.  
  120. SBYTE is used for field coordinates and queue indexes
  121. UBYTE is used for field contents
  122. SWORD is used for frequencies
  123. ULONG is used for scores */
  124.  
  125. struct
  126. {   ABOOL alive, explode, visible;
  127.     SBYTE x, y, deltax, deltay, pos, time, dir;
  128.     UBYTE mode, dormant, multi, speed, last, oldlast, species,
  129.           type; // type is relevant worm 0-3 (for drips, missiles and dogs)
  130.     SWORD armour, tongue, freq;
  131.     ULONG score;
  132. } creature[CREATURES + 1];
  133.  
  134. // MODULE VARIABLES (used only within engine.c) ---------------------------
  135.  
  136. MODULE ABOOL banging = FALSE, letters[4][LETTERS + 1], trainer;
  137. MODULE SBYTE freq, ice, lettertype, letterx, lettery, leveltype,
  138.              treasurer;
  139. MODULE UBYTE infector[FIELDX + 1][FIELDY + 1];
  140. MODULE ULONG octopusspeed;
  141.  
  142. // GLOBAL VARIABLES (owned by engine.c, imported by system.c) -------------
  143.  
  144. ABOOL clearthem  = FALSE,
  145.       modified   = FALSE,
  146.       randomflag = FALSE,
  147.       randomarray[MAXLEVELS + 1];
  148. UBYTE board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
  149.       field[FIELDX + 1][FIELDY + 1];
  150. SBYTE a = GAMEOVER,
  151.       players,
  152.       level = 1, levels, reallevel, sourcelevel,
  153.       startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
  154. SWORD secondsleft, secondsperlevel;
  155. TEXT  pathname[81],
  156.       date[DATELENGTH + 1],
  157.       times[TIMELENGTH + 1];
  158. ULONG delay, r;
  159.  
  160. AGLOBAL struct HiScoreStruct  hiscore[HISCORES + 1];
  161. AGLOBAL struct WormStruct     worm[4];
  162. AGLOBAL struct TeleportStruct teleport[MAXLEVELS + 1][4];
  163.  
  164. /* FUNCTIONS --------------------------------------------------------------
  165.  
  166. NAME        align -- right-justify a string within another string
  167. SYNOPSIS    align(STRPTR, SBYTE, TEXT);
  168. FUNCTION    Moves all text in a string to the right, padding with
  169.             spaces. Does not itself add a null terminator.
  170. INPUTS      string - pointer to the string of text
  171.               size - size in characters of the containing string
  172.             filler - what to pad the left of the string with
  173. NOTE        Null terminators are written over by this function, but that
  174.             does not matter, because calling functions use Text() with an
  175.             explicit length. This function only works with monospaced
  176.             fonts.
  177. MODULE      engine.c */
  178.  
  179. void align(STRPTR string, SBYTE size, TEXT filler)
  180. {   SBYTE i, shift, length;
  181.  
  182.     length = strlen((const char*) string);
  183.     shift = size - length;
  184.     for (i = 1; i <= length; i++)
  185.         *(string + size - i) = *(string + size - i - shift);
  186.     for (i = 0; i <= shift - 1; i++)
  187.         *(string + i) = filler;
  188. }
  189.  
  190. MODULE ABOOL blocked(SBYTE which, SBYTE deltax, SBYTE deltay)
  191. {   UBYTE c = field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)];
  192.     if ((c < STONE || c > GOAT) && c != METAL)
  193.         return FALSE;
  194.     else return TRUE;
  195. }
  196.  
  197. MODULE void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey)
  198. {   SBYTE counter, downy, downymax, leftx, leftxmax, rightx, rightxmax, strength, uppy, uppymax, x, y;
  199.     ULONG score = 0;
  200.  
  201.     effect(FXUSE_BOMB);
  202.  
  203.     strength = BOMBADD + (rand() % BOMBRAND);
  204.  
  205.     leftxmax = centrex - strength;
  206.     if (leftxmax < 0)
  207.         leftxmax = 0;
  208.     rightxmax = centrex + strength;
  209.     if (rightxmax > FIELDX)
  210.         rightxmax = FIELDX;
  211.     uppymax = centrey - strength;
  212.     if (uppymax < 0)
  213.         uppymax = 0;
  214.     downymax = centrey + strength;
  215.     if (downymax > FIELDY)
  216.         downymax = FIELDY;
  217.  
  218.     leftx = centrex;
  219.     rightx = centrex;
  220.     uppy = centrey;
  221.     downy = centrey;
  222.     for (counter = 1; counter <= strength; counter++)
  223.     {   if (leftx > leftxmax)
  224.         {   leftx--;
  225.             for (y = uppy; y <= downy; y++)
  226.                 score += squareblast(triggerer, player, field[leftx][y], leftx, y, FALSE);
  227.         }
  228.         if (rightx < rightxmax)
  229.         {    rightx++;
  230.             for (y = uppy; y <= downy; y++)
  231.                 score += squareblast(triggerer, player, field[rightx][y], rightx, y, FALSE);
  232.         }
  233.         if (uppy > uppymax)
  234.         {    uppy--;
  235.             for (x = leftx; x <= rightx; x++)
  236.                 score += squareblast(triggerer, player, field[x][uppy], x, uppy, FALSE);
  237.         }
  238.         if (downy < downymax)
  239.         {    downy++;
  240.             for (x = leftx; x <= rightx; x++)
  241.                 score += squareblast(triggerer, player, field[x][downy], x, downy, FALSE);
  242.     }    }
  243.  
  244.     if (triggerer == HEAD)
  245.         wormscore(player, score);
  246.     elif (triggerer == ORB)
  247.         orbscore(player, score);
  248.     if (worm[player].bias)
  249.         stat(player, LIFE);
  250. }
  251.  
  252. MODULE void bouncegoat(SBYTE which, SBYTE x, SBYTE y)
  253. {   if (field[x][y] == GOAT)
  254.     {   creature[whichcreature(x, y, GOAT, 255)].alive = FALSE;
  255.         orbscore(which, KILLGOAT);
  256.         change(x, y, BONUS);
  257. }   }
  258.  
  259. MODULE ABOOL bounceorb(SBYTE which, SBYTE x, SBYTE y)
  260. {   if (field[x][y] == METAL)
  261.         return TRUE;
  262.     elif (creature[which].mode == NONE)
  263.     {   if (field[x][y] >= FIRSTNONE && field[x][y] <= LASTNONE)
  264.             return TRUE;
  265.         else return FALSE;
  266.     } elif (creature[which].mode == TONGUE)
  267.     {   if (field[x][y] >= FIRSTTONGUE && field[x][y] <= LASTTONGUE)
  268.             return TRUE;
  269.         else return FALSE;
  270.     } else
  271.     {   // assert(creature[which].mode == ARMOUR);
  272.         if (field[x][y] >= FIRSTARMOUR && field[x][y] <= LASTARMOUR)
  273.             return TRUE;
  274.         else return FALSE;
  275. }   }
  276.  
  277. MODULE SBYTE bsign(SBYTE value)
  278. {   if (value < 0)
  279.         return (-1);
  280.     elif (value > 0)
  281.         return (1);
  282.     else return (0);
  283. }
  284.  
  285. MODULE void changefield(void)
  286. {   SBYTE x, y;
  287.  
  288.     if (randomflag && a == PLAYGAME && level)
  289.     {   do
  290.         {    sourcelevel = (rand() % levels) + 1;
  291.         } while (randomarray[level]);
  292.         randomarray[level] = TRUE;
  293.     } else sourcelevel = level;
  294.  
  295.     for (x = 0; x <= FIELDX; x++)
  296.         for (y = 0; y <= FIELDY; y++)
  297.             field[x][y] = board[sourcelevel][x][y];
  298. }
  299.  
  300. void clearhiscores(void)
  301. {   SBYTE i;
  302.     
  303.     clearthem = FALSE;
  304.     for (i = 0; i <= HISCORES; i++)
  305.     {   hiscore[i].player = -1;
  306.         hiscore[i].level = 0;
  307.         hiscore[i].score = 0;
  308.         hiscore[i].fresh = FALSE;
  309.         hiscore[i].name[0] = 0;
  310.         hiscore[i].time[0] = 0;
  311.         hiscore[i].date[0] = 0;
  312. }   }
  313.  
  314. MODULE void clearletters(void)
  315. {   SBYTE player, which;
  316.  
  317.     for (player = 0; player <= 3; player++)
  318.         for (which = 0; which <= LETTERS; which++)
  319.         {   letters[player][which] = FALSE;
  320.             drawletter(player, FIRSTLETTER + which, BLACK);
  321. }       }
  322.  
  323. MODULE void copyfield(SBYTE source, SBYTE destination)
  324. {   SBYTE which, x, y;
  325.  
  326.     for (x = 0; x <= FIELDX; x++)
  327.         for (y = 0; y <= FIELDY; y++)
  328.             board[destination][x][y] = board[source][x][y];
  329.     startx[destination] = startx[source];
  330.     starty[destination] = starty[source];
  331.     for (which = 0; which <= 1; which++)
  332.     {   teleport[destination][which].alive = teleport[source][which].alive;
  333.         teleport[destination][which].x     = teleport[source][which].x;
  334.         teleport[destination][which].y     = teleport[source][which].y;
  335. }   }
  336.  
  337. MODULE void death(void)
  338. {   SBYTE pain, player, which;
  339.     ABOOL slow;
  340.  
  341.     for (player = 0; player <= 3; player++)
  342.     {   if (worm[player].lives)
  343.         {   if (!worm[player].alive)
  344.             {   slow = FALSE;
  345.                 pain = 0;
  346.                 if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
  347.                 {   if (player == worm[player].cause - FIRSTTAIL)
  348.                         pain = TAILPAIN;
  349.                     else pain = OTHERTAILPAIN;
  350.                     slow = TRUE;
  351.                 } elif (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
  352.                     pain = WORMFIREPAIN;
  353.                 elif (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
  354.                     pain = HEADPAIN;
  355.                 elif (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
  356.                     pain = PROTECTORPAIN;
  357.                 elif (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
  358.                     pain = MISSILEPAIN;
  359.                 elif (worm[player].cause >= FIRSTDRIP && worm[player].cause <= LASTDRIP)
  360.                     pain = DRIPPAIN;
  361.                 else switch (worm[player].cause)
  362.                 {
  363.                 case BOMB:
  364.                     pain = BOMBPAIN;
  365.                 break;
  366.                 case WOOD:
  367.                     pain = WOODPAIN;
  368.                     slow = TRUE;
  369.                 break;
  370.                 case FRAGMENT:
  371.                     pain = FRAGMENTPAIN;
  372.                 break;
  373.                 case GOAT:
  374.                     pain = GOATPAIN;
  375.                     slow = TRUE;
  376.                 break;
  377.                 case OCTOPUS:
  378.                     pain = OCTOPUSPAIN;
  379.                     slow = TRUE;
  380.                 break;
  381.                 case SLAYER:
  382.                     pain = SLAYERPAIN;
  383.                 break;
  384.                 case STONE:
  385.                     pain = STONEPAIN;
  386.                     slow = TRUE;
  387.                 break;
  388.                 case TELEPORT:
  389.                     pain = TELEPORTPAIN;
  390.                     slow = TRUE;
  391.                 break;
  392.                 case SLIME:
  393.                     pain = SLIMEPAIN;
  394.                     slow = TRUE;
  395.                 break;
  396.                 case METAL:
  397.                     pain = METALPAIN;
  398.                     slow = TRUE;
  399.                 break;
  400.                 case REMNANTS:
  401.                     pain = REMNANTPAIN;
  402.                     slow = TRUE;
  403.                 break;
  404.                 case LIGHTNING:
  405.                     pain = LIGHTNINGPAIN;
  406.                 break;
  407.                 case PENGUIN:
  408.                     pain = PENGUINPAIN;
  409.                 break;
  410.                 case WHIRLWIND:
  411.                     pain = WHIRLWINDPAIN;
  412.                 break;
  413.                 case DOG:
  414.                     pain = DOGPAIN;
  415.                 break;
  416.                 case CLOUD:
  417.                     pain = CLOUDPAIN;
  418.                 break;
  419.                 case ORB:
  420.                     pain = ORBPAIN;
  421.                 break;
  422.                 default:
  423.                     // assert(0);
  424.                 break;
  425.                 }
  426.                 if (worm[player].victor >= 0 && worm[player].victor != player)
  427.                 {   wormscore(worm[player].victor, KILLWORM);
  428.                     if (worm[worm[player].victor].bias)
  429.                     {   worm[worm[player].victor].lives += pain;
  430.                         stat(worm[player].victor, LIFE);
  431.                 }   }
  432.                 if (slow)
  433.                 {   worm[player].speed = slowdown(worm[player].speed, worm[player].nitro);
  434.                     stat(player, NITRO); 
  435.                 }
  436.                 if (pain > worm[player].lives)
  437.                     worm[player].lives = 0;
  438.                 else worm[player].lives -= pain;
  439.                 draw(worm[player].x, worm[player].y, SKULL);
  440.                 drawcause(player, NORMAL);
  441.                 stat(player, LIFE);
  442.                 if (level)
  443.                     worm[player].levelreached = level;
  444.                 else worm[player].levelreached = reallevel;
  445.                 if (worm[player].lives)
  446.                 {   effect(FXPAIN + player);
  447.                     worm[player].alive = TRUE;
  448.                     worm[player].causewait = r + CAUSEWAIT;
  449.                 } else
  450.                 {   /* kill worm */
  451.                     effect(FXDEATH_WORM);
  452.                     if (ice == player)
  453.                         ice = -1;
  454.                     field[worm[player].x][worm[player].y] = SKULL;
  455.                     updatearrow(worm[player].y);
  456.                     for (which = 0; which <= PROTECTORS; which++)
  457.                         if (protector[player][which].alive && protector[player][which].visible)
  458.                             change(protector[player][which].x, protector[player][which].y, EMPTY);
  459.                     for (which = 0; which <= MAGNETS; which++)
  460.                         if (magnet[which].player == player)
  461.                             magnet[which].alive = FALSE;
  462.                     if (worm[player].score >= worm[player].hiscore)
  463.                         worm[player].hiscore = worm[player].score;
  464.     }   }   }   }
  465.  
  466.     if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
  467.     {   /* End of game */
  468.         for (player = 0; player <= 3; player++)
  469.             if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  470.                 worm[player].hiscore = worm[player].score;
  471.         newhiscores();
  472.         effect(FXGAMEOVER);
  473.         a = GAMEOVER;
  474.         if (players == 1)
  475.             say((STRPTR) "Game over!", worm[onlyworm(FALSE)].colour);
  476.         elif (worm[0].control && ((!worm[1].control) || worm[1].score < worm[0].score) && ((!worm[2].control) || worm[2].score < worm[0].score) && ((!worm[3].control) || worm[3].score < worm[0].score))
  477.             say((STRPTR) "Green wins!", GREEN);
  478.         elif (worm[1].control && ((!worm[0].control) || worm[0].score < worm[1].score) && ((!worm[2].control) || worm[2].score < worm[1].score) && ((!worm[3].control) || worm[3].score < worm[1].score))
  479.             say((STRPTR) "Red wins!", RED);
  480.         elif (worm[2].control && ((!worm[0].control) || worm[0].score < worm[2].score) && ((!worm[1].control) || worm[1].score < worm[2].score) && ((!worm[3].control) || worm[3].score < worm[2].score))
  481.             say((STRPTR) "Blue wins!", BLUE);
  482.         elif (worm[3].control && ((!worm[0].control) || worm[0].score < worm[3].score) && ((!worm[1].control) || worm[1].score < worm[3].score) && ((!worm[2].control) || worm[2].score < worm[3].score))
  483.             say((STRPTR) "Yellow wins!", YELLOW);
  484.         else say((STRPTR) "A draw!", WHITE);
  485.         waitasec();
  486.         anykey(FALSE);
  487. }   }
  488.  
  489. MODULE void drawcause(SBYTE player, SBYTE state)
  490. {    if (state == BLACK)
  491.                 draw(-2 + ((FIELDX + 5) * worm[player].statx), (FIELDY / 2) - CAUSEYDISTANCE + (worm[player].staty * CAUSEYDISTANCE * 2), BLACKENED);
  492.         else draw(-2 + ((FIELDX + 5) * worm[player].statx), (FIELDY / 2) - CAUSEYDISTANCE + (worm[player].staty * CAUSEYDISTANCE * 2), worm[player].cause);
  493. }
  494.  
  495. MODULE void drawletter(SBYTE player, SBYTE letter, SBYTE state)
  496. {   UBYTE c;
  497.     
  498.     if (state == BLACK)
  499.         c = BLACKENED;
  500.     else c = letter;
  501.     if (!worm[player].statx)
  502.         if (!worm[player].staty)
  503.             draw(-7 + ((letter - FIRSTLETTER) % 4),
  504.                  (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
  505.                  c);
  506.         else
  507.             draw(-7 + ((letter - FIRSTLETTER) % 4),
  508.                  (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
  509.                  c);
  510.     elif (!worm[player].staty)
  511.         draw(FIELDX + 5 + ((letter - FIRSTLETTER) % 4),
  512.              (FIELDY / 2) - 2 + ((letter - FIRSTLETTER) / 4),
  513.              c);
  514.     else
  515.         draw(FIELDX + 5 + ((letter - FIRSTLETTER) % 4),
  516.              (FIELDY / 2) + 1 + ((letter - FIRSTLETTER) / 4),
  517.              c);
  518. }
  519.  
  520. /* NAME     enginesetup -- once-only initialization of engine variables
  521. SYNOPSIS    enginesetup(void);
  522. FUNCTION    Sets up the unchanging worm variables.
  523. MODULE      engine.c */
  524.  
  525. void enginesetup(void)
  526. {   worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
  527.     worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
  528.     worm[0].colour = GREEN;
  529.     worm[1].colour = RED;
  530.     worm[2].colour = BLUE;
  531.     worm[3].colour = YELLOW;
  532.     worm[0].name[0] = worm[1].name[0] = worm[2].name[0] = worm[3].name[0] = 0;
  533.     worm[0].dynamitescore =
  534.     worm[1].dynamitescore =
  535.     worm[2].dynamitescore =
  536.     worm[3].dynamitescore = 0;
  537.  
  538.     strcpy(pathname, DEFAULTSET);
  539.  
  540.     systemsetup();
  541. }
  542.  
  543. /* NAME     fastloop -- things done often
  544. SYNOPSIS    fastloop(void);
  545. FUNCTION    Checks for and handles level completion.
  546. MODULE      engine.c */
  547.  
  548. MODULE void fastloop(void)
  549. {   AUTO ABOOL complete;
  550.     AUTO SBYTE advancer = -1, i, player, which, x, y;
  551.  
  552.     /* update joystick `1' */
  553.     joy0();
  554.     /* update joysticks `3' and `4' */
  555.     ReadAdapterJoystick(2);
  556.     ReadAdapterJoystick(3);
  557.  
  558.     if (!(rand() % octopusspeed))
  559.     {   for (i = 0; i <= CREATURES; i++)
  560.         {   if (creature[i].alive && creature[i].species == OCTOPUS && creature[i].dir >= 0)
  561.             {   octopusfire(i);
  562.     }   }   }
  563.  
  564.     if (banging)
  565.     {   banging = FALSE;
  566.         for (x = 0; x <= FIELDX; x++)
  567.             for (y = 0; y <= FIELDY; y++)
  568.                 if (field[x][y] == BANGDYNAMITE)
  569.                 {   change(x, y, SILVER);
  570.                     bangdynamite(x, y, infector[x][y]);
  571.                 }
  572.         for (i = 0; i <= 3; i++)
  573.             if (worm[i].dynamitescore)
  574.             {   wormscore(i, worm[i].dynamitescore);
  575.                 worm[i].dynamitescore = 0;
  576.             }
  577.         for (x = 0; x <= FIELDX; x++)
  578.             for (y = 0; y <= FIELDY; y++)
  579.                 if (field[x][y] == TEMPBANGDYNAMITE)
  580.                 {   banging = TRUE;
  581.                     field[x][y] = BANGDYNAMITE;
  582.     }           }
  583.  
  584.     /* DYNAMITE PHILOSOPHY:
  585.  
  586.     Worm gets dynamite. Instantly the dynamite infects the surrounding
  587.     dynamite into bang-dynamite.
  588.         Each fastloop, you scan the field for bang-dynamite. For each
  589.     piece you find, it turns to silver and infects any surrounding dynamite.
  590.  
  591.     flash letter */
  592.     if (level)
  593.         if (r % 8 == 1)
  594.             draw(letterx, lettery, WHITENED);
  595.         elif (r % 8 == 2)
  596.             draw(letterx, lettery, lettertype);
  597.  
  598.     // flash icons
  599.  
  600.     for (player = 0; player <= 3; player++)
  601.         {   icon(player, ICE);
  602.             icon(player, FREEDOM);
  603.             icon(player, CUTTER);
  604.     }
  605.  
  606.     /* handle level completion */
  607.     for (player = 0; player <= 3; player++)
  608.     {   complete = TRUE;
  609.         for (which = 0; which <= LETTERS; which++)
  610.             if (!letters[player][which])
  611.                 complete = FALSE;
  612.         if (complete)
  613.             advancer = player;
  614.     }
  615.     if (advancer != -1)
  616.     {   if (level++ == 0)
  617.         {   level = reallevel + 1;
  618.             reallevel = 0;
  619.         }
  620.         stopfx();
  621.         if (level > levels)
  622.             effect(FXCELEBRATE);
  623.         newlevel(advancer);
  624. }   }
  625.  
  626. MODULE ABOOL findempty(SBYTE* x, SBYTE* y, SBYTE first, SBYTE last)
  627. {    SBYTE count = 0, xx, yy;
  628.  
  629.     do
  630.     {    xx = rand() % (FIELDX + 1);
  631.         yy = rand() % (FIELDY + 1);
  632.     } while ((field[xx][yy] < first || field[xx][yy] > last) && ++count < PATIENCE);
  633.     if (count < PATIENCE)
  634.     {    *x = xx;
  635.         *y = yy;
  636.         return(TRUE);
  637.     } else return(FALSE);
  638. }
  639.  
  640. void gameloop(void)
  641. {   SBYTE i, player;
  642.  
  643.     if (a == PLAYGAME)
  644.     {   fastloop();
  645.         gameinput();
  646.     }
  647.     if (a == PLAYGAME)
  648.         for (player = 0; player <= 3; player++)
  649.             if (worm[player].lives && (!(r % worm[player].speed)) && (ice == -1 || ice == player))
  650.                 wormloop(player);
  651.     joy0();
  652.     if (a == PLAYGAME)
  653.         for (i = 0; i <= CREATURES; i++)
  654.             if (creature[i].alive && (!(r % creature[i].speed)) && (ice == -1 || (creature[i].species == MISSILE && ice == creature[i].type)))
  655.                 creatureloop(i);
  656.     joy0();
  657.     if (a == PLAYGAME && !(r % MAGNETSPEED))
  658.         magnetloop();
  659.     joy0();
  660.     if (a == PLAYGAME)
  661.         death();
  662.     joy0();
  663.     if (a == PLAYGAME && !(r % VERYSLOW))
  664.         slowloop();
  665.     joy0();
  666.     timing();
  667. }
  668.  
  669. MODULE void killall(void)
  670. {   UBYTE i;
  671.  
  672.     for (i = 0; i <= CREATURES; i++)
  673.         creature[i].alive = FALSE;
  674.     for (i = 0; i <= MAGNETS; i++)
  675.         magnet[i].alive = FALSE;
  676.     teleport[level][2].alive = FALSE;
  677.     teleport[level][3].alive = FALSE;
  678. }
  679.  
  680. void levelappend(void)
  681. {    UBYTE oldlevel;
  682.  
  683.     if (levels < MAXLEVELS)
  684.     {    oldlevel = level;
  685.         level = ++levels;
  686.         newfield();
  687.         level = oldlevel;
  688.         saylevel(WHITE);
  689. }    }
  690.  
  691. void leveldelete(void)
  692. {    SBYTE i;
  693.  
  694.     /* pull boards */
  695.  
  696.     if (levels > 1)
  697.     {    if (level < levels)
  698.             for (i = level; i < levels; i++)
  699.                 copyfield(i + 1, i);
  700.         else
  701.             level--;
  702.         levels--;
  703.         saylevel(WHITE);
  704.         turborender();
  705. }    }
  706.  
  707. void levelerase(void)
  708. {    newfield();
  709.     turborender();
  710. }
  711.  
  712. void levelinsert(void)
  713. {    SBYTE i;
  714.  
  715.     /* push boards
  716.  */
  717.  
  718.     if (levels < MAXLEVELS)
  719.     {    for (i = levels; i >= level; i--)
  720.             copyfield(i, i + 1);
  721.         levels++;
  722.         saylevel(WHITE);
  723.         newfield();
  724.         turborender();
  725. }    }
  726.  
  727. SBYTE loadfields(STRPTR fieldname)
  728. {   SBYTE i, j, x, y;
  729.     TEXT  IOBuffer[NAMELENGTH + 1];
  730.     UBYTE ver;
  731.  
  732.     /* This routine is not entirely robust, especially regarding
  733.     failures part way through reading. Also, field data values must be
  734.     those supported by the field editor (ie. objects, and the squares
  735.     represented by F1-F8), or undefined behaviour may result. None of
  736.     this is currently checked for. Provided that the fieldset was
  737.     created with the official field editor, and the file is not
  738.     corrupt, these failures should never happen anyway.
  739.  
  740.     open file */
  741.  
  742.     // say("Opening...", WHITE);
  743.  
  744.     if (!ZOpen(fieldname, FALSE))
  745.         return 1; /* no harm done */
  746.  
  747.     /* read header */
  748.  
  749.     // say("Reading header...", WHITE);
  750.  
  751.     if (!ZRead(IOBuffer, 10))
  752.     {    ZClose();
  753.         return 2; /* no harm done */
  754.     }
  755.     if (!strcmp(IOBuffer, "FSET 6.6"))
  756.         ver = 66;
  757.     elif (!strcmp(IOBuffer, "FSET 6.3"))
  758.         ver = 63;
  759.     elif (!strcmp(IOBuffer, "FSET 6.2"))
  760.         ver = 62;
  761.     elif (!strcmp(IOBuffer, "FSET 6.0"))
  762.         ver = 60;
  763.     elif (!strcmp(IOBuffer, "FSET 5.6"))
  764.         ver = 56;
  765.     elif (!strcmp(IOBuffer, "FSET 5.5"))
  766.         ver = 55;
  767.     elif (!strcmp(IOBuffer, "FSET 5.3"))
  768.         ver = 53;
  769.     elif (!strcmp(IOBuffer, "FSET 5.1"))
  770.         ver = 51;
  771.     elif (!strcmp(IOBuffer, "FSET 5.0"))
  772.         ver = 50;
  773.     else
  774.     {   ZClose();
  775.         return 3; /* no harm done */
  776.     }
  777.     levels = IOBuffer[9];
  778.  
  779.     /* read high score table */
  780.  
  781.     // say("Reading high score table...", WHITE);
  782.  
  783.     for (i = 0; i <= HISCORES; i++)
  784.     {   if (!ZRead(IOBuffer, 6))
  785.         {    ZClose();
  786.              return 4; /* incorrect levels */
  787.         }
  788.         hiscore[i].fresh                        =  FALSE;
  789.         hiscore[i].player                       =  IOBuffer[0];
  790.         hiscore[i].level                        =  IOBuffer[1];
  791.         hiscore[i].score                        = (IOBuffer[2] * 16777216)
  792.                                                 + (IOBuffer[3] * 65536)
  793.                                                 + (IOBuffer[4] * 256)
  794.                                                 +  IOBuffer[5];
  795.  
  796.         if (!ZRead(IOBuffer, NAMELENGTH + 1))
  797.         {   ZClose();
  798.             return 5; /* incorrect levels, corrupted high scores */
  799.         }
  800.         for (j = 0; j <= NAMELENGTH; j++)
  801.         {   hiscore[i].name[j]              = IOBuffer[j];
  802.         }
  803.         if (!ZRead(IOBuffer, TIMELENGTH + 1))
  804.         {   ZClose();
  805.             return 6; /* incorrect levels, corrupted high scores */
  806.         }
  807.         for (j = 0; j <= TIMELENGTH; j++)
  808.         {   hiscore[i].time[j]      = IOBuffer[j];
  809.         }
  810.         if (!ZRead(IOBuffer, DATELENGTH + 1))
  811.         {   ZClose();
  812.             return 7; /* incorrect levels, corrupted high scores */
  813.         }
  814.         for (j = 0; j <= DATELENGTH; j++)
  815.         {   hiscore[i].date[j]      = IOBuffer[j];
  816.     }   }
  817.  
  818.     // say("Reading level data...", WHITE);
  819.  
  820.     /* read level data */
  821.  
  822.     for (i = 0; i <= levels; i++)
  823.     {   if (!ZRead(IOBuffer, 8))
  824.         {   ZClose();
  825.             return 9;
  826.             /* incorrect levels, corrupted high scores,
  827.             incorrect startx, teleports, field data */
  828.         }
  829.         startx[i]            =  IOBuffer[0];
  830.         starty[i]            =  IOBuffer[1];
  831.         teleport[i][0].alive =  IOBuffer[2];
  832.         teleport[i][0].x     =  IOBuffer[3];
  833.         teleport[i][0].y     =  IOBuffer[4];
  834.         teleport[i][1].alive =  IOBuffer[5];
  835.         teleport[i][1].x     =  IOBuffer[6];
  836.         teleport[i][1].y     =  IOBuffer[7];
  837.  
  838.         if (!ZRead((char *) &board[i][0][0], LEVELSIZE))
  839.         {   ZClose();
  840.             return 10;
  841.             /* incorrect levels, corrupted high scores,
  842.             incorrect startx, teleports, field data */
  843.         } else
  844.         {   if (ver <= 50)
  845.             {   // convert from FSET 5.0 to FSET 5.1 format
  846.                 for (x = 0; x <= FIELDX; x++)
  847.                      for (y = 0; y <= FIELDY; y++)
  848.                           if (board[i][x][y] >= 11)
  849.                               board[i][x][y]++;
  850.             }
  851.             if (ver <= 51)
  852.             {   // convert from FSET 5.1 to FSET 5.3 format
  853.                 for (x = 0; x <= FIELDX; x++)
  854.                     for (y = 0; y <= FIELDY; y++)
  855.                         if (board[i][x][y] >= 7 && board[i][x][y] <= 63)
  856.                             board[i][x][y]++;
  857.             }
  858.             if (ver <= 53)
  859.             {   // convert from FSET 5.3 to FSET 5.5 format
  860.                 for (x = 0; x <= FIELDX; x++)
  861.                     for (y = 0; y <= FIELDY; y++)
  862.                         if (board[i][x][y] >= 20)
  863.                             board[i][x][y]++;
  864.             }
  865.             if (ver <= 55)
  866.             {   // convert from FSET 5.5 to FSET 5.6 format
  867.                 for (x = 0; x <= FIELDX; x++)
  868.                     for (y = 0; y <= FIELDY; y++)
  869.                         if (board[i][x][y] >= 13)
  870.                             board[i][x][y]++;
  871.             }
  872.             if (ver <= 56)
  873.             {   // convert from FSET 5.6 to FSET 6.0 format
  874.                 for (x = 0; x <= FIELDX; x++)
  875.                     for (y = 0; y <= FIELDY; y++)
  876.                         if (board[i][x][y] >= 8 && board[i][x][y] <= 20)
  877.                             board[i][x][y]++;
  878.                         elif (board[i][x][y] >= 21)
  879.                             board[i][x][y] += 2;
  880.             }
  881.             if (ver <= 60)
  882.             {   // convert from FSET 6.0 to FSET 6.2 format
  883.                 for (x = 0; x <= FIELDX; x++)
  884.                     for (y = 0; y <= FIELDY; y++)
  885.                         if (board[i][x][y] >= 7)
  886.                             board[i][x][y]++;
  887.             }
  888.             if (ver <= 62)
  889.             {   // convert from FSET 6.2 to FSET 6.3/6.6 format
  890.                 for (x = 0; x <= FIELDX; x++)
  891.                     for (y = 0; y <= FIELDY; y++)
  892.                         if (board[i][x][y] >= 7)
  893.                             board[i][x][y]++;
  894.     }   }   }
  895.  
  896.     // say("Open done.", WHITE);
  897.  
  898.     // no need to read version string
  899.     ZClose();
  900.     modified = FALSE;
  901.     return 0;
  902. }
  903.  
  904. MODULE void magnetloop(void)
  905. {   SBYTE i;
  906.     UBYTE c;
  907.  
  908.     for (i = 0; i <= MAGNETS; i++)
  909.     {   if (magnet[i].alive)
  910.         {   // defensive programming to ensure magnet is still valid
  911.             if (field[magnet[i].x][magnet[i].y] != magnet[i].object)
  912.             {   magnet[i].alive = FALSE;
  913.             } else
  914.             {   change(magnet[i].x, magnet[i].y, EMPTY);
  915.                 magnet[i].x += bsign(worm[magnet[i].player].x - magnet[i].x);
  916.                 magnet[i].y += bsign(worm[magnet[i].player].y - magnet[i].y);
  917.                 c = field[magnet[i].x][magnet[i].y];
  918.            
  919.                 if ((c >= FIRSTEMPTY && c <= LASTEMPTY)
  920.                  || (c >= FIRSTTAIL  && c <= LASTTAIL))
  921.                     change(magnet[i].x, magnet[i].y, magnet[i].object);
  922.                 elif (c >= FIRSTHEAD && c <= LASTHEAD)
  923.                 {   change(magnet[i].x, magnet[i].y, magnet[i].object);
  924.                     wormscore(c - FIRSTHEAD, wormobject(c - FIRSTHEAD, magnet[i].x, magnet[i].y));
  925.                     change(magnet[i].x, magnet[i].y, FIRSTHEAD + magnet[i].player); // not entirely the right head image
  926.                 } else magnet[i].alive = FALSE;
  927. }   }   }   }
  928.  
  929. AGLOBAL void matchteleports(void)
  930. {   AUTO UWORD teleports, octopi;
  931.     AUTO SBYTE x, y, i;
  932.  
  933.     say("Checking fieldset...", WHITE);
  934.     for (i = 0; i <= levels; i++)
  935.     {   teleports = octopi = 0;
  936.         teleport[level][0].alive = teleport[level][1].alive = FALSE;
  937.  
  938.         for (y = 0; y <= FIELDY; y++)
  939.         {   for (x = 0; x <= FIELDX; x++)
  940.             {   if (board[level][x][y] == TELEPORT)
  941.                 {   teleports++;
  942.                     if (teleports <= 2)
  943.                     {   teleport[level][teleports - 1].x = x;
  944.                         teleport[level][teleports - 1].y = y;
  945.                     } else
  946.                     {   board[level][x][y] = EMPTY;
  947.                 }   }
  948.                 elif (board[level][x][y] == OCTOPUS)
  949.                 {   octopi++;
  950.                     if (octopi > 12)
  951.                     {   board[level][x][y] = EMPTY;
  952.         }   }   }   }
  953.  
  954.         if (teleports == 1)
  955.         {   board[level][teleport[level][0].x][teleport[level][0].y] = EMPTY;
  956.         } elif (teleports >= 2)
  957.         {   teleport[level][0].alive = teleport[level][1].alive = TRUE;
  958. }   }   }
  959.  
  960. MODULE void newfield(void)
  961. {   SBYTE x, y;
  962.  
  963.     teleport[level][0].alive = FALSE;
  964.     teleport[level][1].alive = FALSE;
  965.     startx[level] = FIELDX / 2;
  966.     starty[level] = FIELDY / 2;
  967.  
  968.     if (level)
  969.         for (x = 0; x <= FIELDX; x++)
  970.             for (y = 0; y <= FIELDY; y++)
  971.                 board[level][x][y] = EMPTY;
  972.     else for (x = 0; x <= FIELDX; x++)
  973.         for (y = 0; y <= FIELDY; y++)
  974.             board[0][x][y] = SILVER;
  975. }
  976.  
  977. void newfields(void)
  978. {   if (verify())
  979.     {   strcpy(pathname, DEFAULTSET);
  980.         levels = DEFAULTLEVELS;
  981.         modified = FALSE;
  982.         for (level = 0; level <= levels; level++)
  983.             newfield();
  984.         clearhiscores();
  985.         level = 1;
  986.         if (a == FIELDEDIT)
  987.         {    turborender();
  988.             saylevel(WHITE);
  989.         } else hiscores();
  990. }    }
  991.  
  992. void newgame(void)
  993. {   SBYTE i, player;
  994.  
  995.     players = 0;
  996.     for (player = 0; player <= 3; player++)
  997.     {   if (worm[player].control != NONE)
  998.             players++;
  999.         worm[player].lives = 0;
  1000.         worm[player].speed = NORMAL;
  1001.         worm[player].hiscore = 0;
  1002.     }
  1003.     for (i = 1; i <= MAXLEVELS; i++)
  1004.        randomarray[i] = FALSE;
  1005.  
  1006.     r         = -1;
  1007.     trainer   = FALSE;
  1008.     ice       = -1;
  1009.     reallevel = 0;
  1010.  
  1011.     level     = 1;
  1012.     a         = PLAYGAME;
  1013.     clearscreen();
  1014.     newlevel(rand() % 4);
  1015.     timing();
  1016. }
  1017.  
  1018. MODULE void newhiscores(void)
  1019. {   PERSIST TEXT  amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R. J. Mical", "Dave Morse"};
  1020.     AUTO    SBYTE i, j, player;
  1021.  
  1022.     datestamp();
  1023.     for (player = 0; player <= 3; player++)
  1024.         for (i = 0; i <= HISCORES; i++)
  1025.             if (worm[player].control != NONE && worm[player].score >= hiscore[i].score)
  1026.             {   /* push all worse hiscores down */
  1027.  
  1028.                 if (i < HISCORES)
  1029.                     for (j = HISCORES; j >= i + 1; j--)
  1030.                     {   hiscore[j].player     = hiscore[j - 1].player;
  1031.                         hiscore[j].level      = hiscore[j - 1].level;
  1032.                         hiscore[j].score      = hiscore[j - 1].score;
  1033.                         hiscore[j].fresh      = hiscore[j - 1].fresh;
  1034.                         strcpy(hiscore[j].name, hiscore[j - 1].name);
  1035.                         strcpy(hiscore[j].date, hiscore[j - 1].date);
  1036.                         strcpy(hiscore[j].time, hiscore[j - 1].time);
  1037.                     }
  1038.                 modified = TRUE;
  1039.                 hiscore[i].player = player;
  1040.                 hiscore[i].level  = worm[player].levelreached;
  1041.                 hiscore[i].score  = worm[player].hiscore;
  1042.                 if (worm[player].control == AMIGA)
  1043.                 {   strcpy(hiscore[i].name, amiganame[player]);
  1044.                     hiscore[i].fresh = FALSE;
  1045.                 } else
  1046.                 {   strcpy(hiscore[i].name, "(New)");
  1047.                     hiscore[i].fresh = TRUE;
  1048.                 }
  1049.                 strcpy(hiscore[i].time, times);
  1050.                 strcpy(hiscore[i].date, date);
  1051.                 break; /* vital */
  1052. }           }
  1053.  
  1054. MODULE void newlevel(SBYTE player)
  1055. {   SBYTE i, j;
  1056.     UWORD octopi = 0;
  1057.     UBYTE x, y;
  1058.  
  1059.     if (level >= 2)
  1060.         rundown(player);
  1061.     if (a == PLAYGAME)
  1062.     {   if (level > levels)
  1063.         {   for (i = 0; i <= 3; i++)
  1064.             {   if (worm[i].lives)
  1065.                     worm[i].levelreached = -1;
  1066.                 if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  1067.                     worm[player].hiscore = worm[player].score;
  1068.             }
  1069.             celebrate();
  1070.             newhiscores();
  1071.             titlescreen();
  1072.         } else
  1073.         {   saylevel(WHITE);
  1074.             for (i = 0; i <= 3; i++)
  1075.             {   worm[i].multi = (SBYTE) atleast(worm[i].multi / 2, 1);
  1076.                 worm[i].remnants = FALSE;
  1077.                 worm[i].pusher = FALSE;
  1078.             }
  1079.             killall();
  1080.             clearletters();
  1081.             changefield();
  1082.             octopusspeed = FAST;
  1083.             for (x = 0; x <= FIELDX; x++)
  1084.             {   for (y = 0; y <= FIELDY; y++)
  1085.                 {   if (board[level][x][y] == OCTOPUS)
  1086.                     {   octopi++;
  1087.                         if (octopi <= 12)
  1088.                         {   creature[octopi].alive   = TRUE;
  1089.                             creature[octopi].species = OCTOPUS;
  1090.                             creature[octopi].visible = TRUE;
  1091.                             creature[octopi].x       = x;
  1092.                             creature[octopi].y       = y;
  1093.                             creature[octopi].speed   = VERYSLOW;
  1094.                             creature[octopi].dir     = -1;
  1095.                             creature[octopi].deltax  = creature[octopi].deltay = 0;
  1096.             }   }   }   }
  1097.             for (i = 0; i <= 3; i++)
  1098.             {   worm[i].speed = NORMAL;
  1099.                 if (worm[i].lives)
  1100.                     stat(i, NITRO);
  1101.                 worm[i].moved = FALSE;
  1102.                 worm[i].x = startx[sourcelevel];
  1103.                 worm[i].y = starty[sourcelevel];
  1104.                 worm[i].arrowy = worm[i].y;
  1105.         switch(i)
  1106.         {
  1107.         case 0:
  1108.             worm[0].deltax = -1;
  1109.             worm[0].deltay = 0;
  1110.         break;
  1111.         case 1:
  1112.             worm[1].deltax = 1;
  1113.             worm[1].deltay = 0;
  1114.         break;
  1115.         case 2:
  1116.             worm[2].deltax = 0;
  1117.             worm[2].deltay = -1;
  1118.         break;
  1119.         case 3:
  1120.             worm[3].deltax = 0;
  1121.             worm[3].deltay = 1;
  1122.         break;
  1123.         default:
  1124.         break;
  1125.             }   }
  1126.             turborender();
  1127.             delay = atleast(DELAY_MAX - (level * DELAY_DEC), DELAY_MIN);
  1128.  
  1129.             if (level)
  1130.             {   secondsperlevel = SECONDSPERLEVEL;
  1131.                 putletter(-1);
  1132.                 freq = (SBYTE) atleast(FREQ_MAX - (level * FREQ_DEC), FREQ_MIN);
  1133.                 for (i = 0; i <= 3; i++)
  1134.                 {   if (!worm[i].lives && worm[i].control != NONE)
  1135.                     {   /* create (or resurrect) a worm */
  1136.  
  1137.                         worm[i].lives      = STARTLIVES;
  1138.                         worm[i].score      = 0;
  1139.                         worm[i].oldscore   = 0;
  1140.                         worm[i].armour     = 0;
  1141.                         worm[i].tongue     = 0;
  1142.                         worm[i].alive      = TRUE;
  1143.                         worm[i].nitro      = FALSE;
  1144.                         worm[i].flashed    = FALSE;
  1145.                         worm[i].mode       = NOMODE;
  1146.                         worm[i].power      = 0;
  1147.                         worm[i].bias       = 0;
  1148.                         worm[i].multi      = 1;
  1149.                         worm[i].ice        = 0;
  1150.                         worm[i].victor     = -1;
  1151.                         worm[i].ammo       = 0;
  1152.                         worm[i].remnants   = FALSE;
  1153.                         worm[i].affixer    = FALSE;
  1154.                         worm[i].sideshot   = FALSE;
  1155.                         worm[i].pusher     = FALSE;
  1156.                         worm[i].rammed     = FALSE;
  1157.                         worm[i].freedom    = 0;
  1158.                         worm[i].causewait  = (ULONG) -1;
  1159.                         worm[i].last       = FIRSTTAIL + i;
  1160.                         worm[i].pos        = -1;
  1161.                         worm[i].cutter     = 0;
  1162.                         for (j = 0; j <= PROTECTORS; j++)
  1163.                             protector[i][j].alive = FALSE;
  1164.                         for (j = 0; j <= LASTOBJECT; j++)
  1165.                             stat(i, j);
  1166.             }   }   }
  1167.             icon(i, ICE);
  1168.             icon(i, REMNANTS);
  1169.             icon(i, AFFIXER);
  1170.             icon(i, SIDESHOT);
  1171.             icon(i, PUSHER);
  1172.             icon(i, FREEDOM);
  1173.             icon(i, CUTTER);
  1174.     }   }
  1175.     clearjoystick();
  1176.     clearkybd();
  1177.     resettime();
  1178. }
  1179.  
  1180. MODULE void explosion(SBYTE x, SBYTE y, SBYTE exceptionx, SBYTE exceptiony, UBYTE creator)
  1181. {   UBYTE i, generated = 0;
  1182.  
  1183.     effect(FXGET_PULSE);
  1184.     for (i = 0; i <= CREATURES; i++)
  1185.     {   if ((!(creature[i].alive)) && generated <= 7)
  1186.         {   if (creator == OCTOPUS)
  1187.             {   creature[i].last = OCTOPUS;
  1188.                 creature[i].visible = FALSE;
  1189.             } else
  1190.             {   creature[i].last = EMPTY;
  1191.                 creature[i].visible = TRUE;
  1192.             }
  1193.             creature[i].x = x;
  1194.             creature[i].y = y;
  1195.             if (level)
  1196.             {   creature[i].speed = (SBYTE) atleast(FRAGSPEED - (level / 2), 1);
  1197.             } else creature[i].speed = BONUSFRAGSPEED;
  1198.         creature[i].species   = FRAGMENT;
  1199.  
  1200.             switch (generated)
  1201.             {
  1202.             case 0:
  1203.                 creature[i].deltax = 0;
  1204.                 creature[i].deltay = -1;
  1205.             break;
  1206.             case 1:
  1207.                 creature[i].deltax = 1;
  1208.                 creature[i].deltay = -1;
  1209.             break;
  1210.             case 2:
  1211.                 creature[i].deltax = 1;
  1212.                 creature[i].deltay = 0;
  1213.             break;
  1214.             case 3:
  1215.                 creature[i].deltax = 1;
  1216.                 creature[i].deltay = 1;
  1217.             break;
  1218.             case 4:
  1219.                 creature[i].deltax = 0;
  1220.                 creature[i].deltay = 1;
  1221.             break;
  1222.             case 5:
  1223.                 creature[i].deltax = -1;
  1224.                 creature[i].deltay = 1;
  1225.             break;
  1226.             case 6:
  1227.                 creature[i].deltax = -1;
  1228.                 creature[i].deltay = 0;
  1229.             break;
  1230.             case 7:
  1231.                 creature[i].deltax = -1;
  1232.                 creature[i].deltay = -1;
  1233.             break;
  1234.             default:
  1235.             break;
  1236.             }
  1237.  
  1238.             generated++;
  1239.             if (creature[i].deltax != exceptionx || creature[i].deltay != exceptiony)
  1240.             {   creature[i].alive = TRUE;
  1241.                 if (generated == 1 && creator != OCTOPUS)
  1242.                 {   change(x, y, FRAGMENT);
  1243. }   }   }   }   }
  1244.  
  1245. /* Many creatures take advantage of shared characteristics.
  1246. 11 creature types (orbs, goats, drips, fragments, missiles, penguins,
  1247. cyclones, dogs, clouds, timebombs, octopus) use the creature structure.
  1248. Independent of it are worms, protectors, worm bullets and teleports. */
  1249.  
  1250. MODULE void creatureloop(SBYTE which)
  1251. {   ABOOL   happy = FALSE;
  1252.     UBYTE   bestdistance = 255, distance, player, c, i;
  1253.     SBYTE   x, y, xx, yy, xxx, yyy, frontx, fronty, rearx, reary;
  1254.  
  1255.     x = creature[which].x;
  1256.     y = creature[which].y;
  1257.  
  1258.     if (!valid(x, y)) // defensive programming
  1259.     {   creature[which].alive = FALSE;
  1260.         return;
  1261.  
  1262.         /* TEXT temp1[SAYLIMIT + 1], temp2[8];
  1263.  
  1264.         strcpy(temp1, "BAD CREATURE AT x: ");
  1265.         stci_d(temp2, x);
  1266.         strcat(temp1, temp2);
  1267.         strcat(temp1, ", y: ");
  1268.         stci_d(temp2, y);
  1269.         strcat(temp1, temp2);
  1270.         strcat(temp1, "!");
  1271.         say(temp1, PURPLE);
  1272.         draw(FIELDX + 1, 0, creature[which].species); // indicates which creature
  1273.         Delay(250);
  1274.         clearkybd();
  1275.         anykey(FALSE); */
  1276.     }
  1277.  
  1278.     if (creature[which].species == ORB && creature[which].explode)
  1279.     {   creature[which].alive = FALSE;
  1280.         explosion(x, y, -2, -2, ORB);
  1281.         return;
  1282.     }
  1283.  
  1284. /* decide whether and where to move */
  1285.  
  1286. switch(creature[which].species)
  1287. {
  1288. case CLOUD:
  1289.         if (creature[which].x == 0 || creature[which].x == FIELDX)
  1290.             creature[which].deltax = -creature[which].deltax;
  1291. break;
  1292. case TIMEBOMB:
  1293.     /* decrement and explode timebombs */
  1294.         if (field[x][y] != TIMEBOMB)
  1295.             creature[which].alive = FALSE;
  1296.         else
  1297.         {   effect(FXDO_BOMB);
  1298.             creature[which].time--;
  1299.             if (creature[which].time < 0)
  1300.             {   creature[which].alive = FALSE;
  1301.                 bombblast(BOMB, 0, x, y);
  1302.                 change(x, y, EMPTY);
  1303.             } else draw(x, y, ZERO + creature[which].time);
  1304.         }
  1305.         return; // not a bug
  1306. break;
  1307. case DOG:
  1308.         /* remove a movement from the dog queue */
  1309.  
  1310.         if (creature[which].dormant == CHASING)
  1311.         {   if (creature[which].pos != -1)
  1312.             {   creature[which].deltax = thedogqueue[which][0].deltax;
  1313.                 creature[which].deltay = thedogqueue[which][0].deltay;
  1314.                 if (--creature[which].pos != -1)
  1315.                 {   for (i = 0; i <= creature[which].pos; i++)
  1316.                     {   thedogqueue[which][i].deltax = thedogqueue[which][i + 1].deltax;
  1317.                         thedogqueue[which][i].deltay = thedogqueue[which][i + 1].deltay;
  1318.             }   }   }
  1319.             else creature[which].alive = FALSE;
  1320.         }
  1321. break;
  1322. case PENGUIN:
  1323.     do
  1324.     {    xx = (rand() % 3) - 1;
  1325.         yy = (rand() % 3) - 1;
  1326.     } while (!valid(x + xx, y + yy));
  1327.         c = field[x + xx][y + yy];
  1328.         if (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1329.     {    creature[which].deltax = xx;
  1330.         creature[which].deltay = yy;
  1331.     } else
  1332.     {    creature[which].deltax = 0;
  1333.         creature[which].deltay = 0;
  1334.     }
  1335. break;
  1336. case WHIRLWIND:
  1337.     /* Whirlwinds has a slight upwards drift.
  1338.     Higher values of UNDRIFT make it less buoyant. */
  1339.  
  1340.     creature[which].deltax = (rand() % 3) - 1;
  1341.     if (!(rand() % UNDRIFT))
  1342.         creature[which].deltay = (rand() % 2) - 1;
  1343.     else creature[which].deltay = (rand() % 3) - 1;
  1344. break;
  1345. case MISSILE:
  1346.     for (player = 0; player <= 3; player++)
  1347.     {   if (creature[which].type != player && worm[player].lives && (!worm[player].bias))
  1348.         {   xx = abs(worm[player].x - x);
  1349.             yy = abs(worm[player].y - y);
  1350.             if (xx < yy)
  1351.                 distance = xx;
  1352.             else distance = yy;
  1353.             if (distance <= bestdistance)
  1354.             {   bestdistance = distance;
  1355.                 creature[which].deltax = bsign(worm[player].x - x);
  1356.                 creature[which].deltay = bsign(worm[player].y - y);
  1357.         }   }
  1358.     for (i = 0; i <= CREATURES; i++)
  1359.             if (creature[i].alive && which != i)
  1360.             {   if
  1361.                 (   creature[i].species == ORB
  1362.                 ||  (creature[i].species == MISSILE && creature[i].type != creature[which].type)
  1363.                 ||  creature[i].species == GOAT
  1364.                 )
  1365.                 {   xx = abs(creature[i].x - x);
  1366.                     yy = abs(creature[i].y - y);
  1367.                     if (xx < yy)
  1368.                         distance = xx;
  1369.                     else distance = yy;
  1370.                     if (distance <= bestdistance)
  1371.                     {   bestdistance = distance;
  1372.                         creature[which].deltax = bsign(creature[i].x - x);
  1373.                         creature[which].deltay = bsign(creature[i].y - y);
  1374.     }       }   }   }
  1375.     if (bestdistance == 255)
  1376.         creature[which].alive = FALSE;
  1377. break;
  1378. case ORB:
  1379.     frontx  = xwrap(x + creature[which].deltax);  /* look in front */
  1380.     fronty  = ywrap(y + creature[which].deltay);
  1381.     rearx   = xwrap(x - creature[which].deltax);  /* look behind */
  1382.     reary   = ywrap(y - creature[which].deltay);
  1383.     if (bounceorb(which, frontx, fronty))
  1384.     {   bouncegoat(which, frontx, fronty);
  1385.         xx = -creature[which].deltax; /* default bounce angle is 180° */
  1386.         yy = -creature[which].deltay;
  1387.         if (!bounceorb(which, frontx, reary))
  1388.         {    if (bounceorb(which, rearx, fronty))
  1389.             {   bouncegoat(which, rearx, fronty);
  1390.                 xx = creature[which].deltax;
  1391.         }    }
  1392.         elif (!bounceorb(which, rearx, fronty))
  1393.         {   bouncegoat(which, rearx, fronty);
  1394.             yy = creature[which].deltay;
  1395.         }
  1396.         creature[which].deltax = xx;
  1397.         creature[which].deltay = yy;
  1398.     }
  1399. break;
  1400. case GOAT:
  1401.     /* decide whether to move */
  1402.     if (!(rand() % GOATMOVE))
  1403.     {   for (xx = x - 1; xx <= x + 1; xx++)
  1404.             for (yy = y - 1; yy <= y + 1; yy++)
  1405.                 if (valid(xx, yy) && field[xx][yy] >= FIRSTEMPTY && field[xx][yy] <= LASTEMPTY)
  1406.                 {   happy = TRUE;
  1407.                     break;
  1408.     }            }
  1409.     creature[which].deltax = 0;
  1410.     creature[which].deltay = 0;
  1411.     if (!happy)
  1412.     {    xx = (rand() % 3) - 1;
  1413.         yy = (rand() % 3) - 1;
  1414.         if (valid(x + xx, y + yy) && (xx || yy))
  1415.                 {       c = field[x + xx][y + yy];
  1416.             if (c >= FIRSTGOAT && c <= LASTGOAT && c != GOAT)
  1417.             {    creature[which].last = creature[which].oldlast;
  1418.                                 creature[which].oldlast = c;
  1419.                 creature[which].deltax = xx;
  1420.                 creature[which].deltay = yy;
  1421.     }    }    }
  1422. break;
  1423. default:
  1424. break;
  1425. }
  1426.  
  1427. /* now move */
  1428.  
  1429. if (creature[which].deltax || creature[which].deltay)
  1430. {    if (creature[which].visible)
  1431.     {   /* erase previous image */
  1432.         change(x, y, creature[which].last);
  1433.             creature[which].last = EMPTY;
  1434.     }
  1435.     if (creature[which].alive)
  1436.     {   creature[which].x += creature[which].deltax;
  1437.         creature[which].y += creature[which].deltay;
  1438.         if (creature[which].species == ORB)
  1439.         {   creature[which].x = xwrap(creature[which].x);
  1440.             creature[which].y = ywrap(creature[which].y);
  1441.         } elif (creature[which].species == FRAGMENT || creature[which].species == DRIP || creature[which].species == WHIRLWIND || creature[which].species == DOG)
  1442.         {    if (!valid(creature[which].x, creature[which].y))
  1443.                 creature[which].alive = FALSE;
  1444. }    }   }
  1445.  
  1446. creature[which].visible = TRUE;
  1447. x = creature[which].x;
  1448. y = creature[which].y;
  1449.  
  1450. /* Collision detection.
  1451. Timebombs don't need to go through this. */
  1452.  
  1453. if
  1454. (    creature[which].alive
  1455.  &&  creature[which].species != GOAT
  1456.  &&  creature[which].species != PENGUIN
  1457.  &&  creature[which].species != OCTOPUS
  1458.  && (creature[which].deltax || creature[which].deltay)
  1459. )
  1460. {   c = field[x][y];
  1461.  
  1462.     if (c >= FIRSTHEAD && c <= LASTHEAD)
  1463.     {   if (creature[which].species == MISSILE)
  1464.             wormmissile(x, y, c - FIRSTHEAD, which);
  1465.         elif (creature[which].species == DOG)
  1466.             wormdog(x, y, c - FIRSTHEAD, which);
  1467.         elif (creature[which].species == FRAGMENT)
  1468.             wormfrag(x, y, c - FIRSTHEAD, which);
  1469.         elif (creature[which].species == DRIP)
  1470.             wormdrip(x, y, c - FIRSTHEAD, which);
  1471.         elif (creature[which].species == WHIRLWIND)
  1472.             wormwhirlwind(x, y, c - FIRSTHEAD, which);
  1473.         elif (creature[which].species == CLOUD)
  1474.             cloudworm(x, y, which, c - FIRSTHEAD);
  1475.         elif (creature[which].species == ORB)
  1476.         {   wormorb(x, y, c - FIRSTHEAD, which);
  1477.             creature[which].last = c - FIRSTHEAD + FIRSTTAIL; /* note sign issues */
  1478.     }   }
  1479.     elif (c == TIMEBOMB)
  1480.     {   creature[whichcreature(x, y, TIMEBOMB, which)].alive = FALSE;
  1481.         bombblast(BOMB, 0, x, y);
  1482.         change(x, y, EMPTY);
  1483.     } elif (c == OCTOPUS)
  1484.     {   if (creature[which].species == ORB)
  1485.         {   effect(FXDEATH_ORB);
  1486.         } elif (creature[which].species == FRAGMENT)
  1487.         {   effect(FXDEATH_FRAGMENT);
  1488.         }
  1489.         creature[which].alive = FALSE;
  1490.     } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  1491.     {   if (creature[which].species == ORB)
  1492.         {   if (creature[which].mode == TONGUE)
  1493.                 effect(FXUSE_TONGUE);
  1494.             else
  1495.             {   if (worm[c - FIRSTTAIL].alive)
  1496.                 {   effect(FXDEATH_ORB);
  1497.                     wormscore(c - FIRSTTAIL, creature[which].score);
  1498.                     if (worm[c - FIRSTTAIL].bias)
  1499.                     {   worm[c - FIRSTTAIL].lives += ORBBLOOD;
  1500.                         stat(c - FIRSTTAIL, LIFE);
  1501.                 }   }
  1502.                 creature[which].alive = FALSE;
  1503.                 change(x, y, BONUS);
  1504.     }   }   }
  1505.     elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  1506.     {   if (creature[which].species == DOG)
  1507.             protdog(x, y, c - FIRSTPROTECTOR, which);
  1508.         elif (creature[which].species == DRIP)
  1509.             protdrip(x, y, c - FIRSTPROTECTOR, which);
  1510.         elif (creature[which].species == MISSILE)
  1511.             protmissile(x, y, c - FIRSTPROTECTOR, which);
  1512.         elif (creature[which].species == FRAGMENT)
  1513.             protfrag(x, y, c - FIRSTPROTECTOR, which);
  1514.         elif (creature[which].species == ORB)
  1515.             protorb(x, y, c - FIRSTPROTECTOR, which);
  1516.         elif (creature[which].species == PENGUIN)
  1517.             protpenguin(x, y, c - FIRSTPROTECTOR, which);
  1518.         elif (creature[which].species == WHIRLWIND)
  1519.             protwhirlwind(x, y, c - FIRSTPROTECTOR, which);
  1520.         elif (creature[which].species == CLOUD)
  1521.             cloudprot(x, y, which, c - FIRSTPROTECTOR);
  1522.     } elif (c >= FIRSTLETTER && c <= LASTLETTER)
  1523.     {   if (creature[which].species == DRIP || creature[which].species == FRAGMENT || creature[which].species == MISSILE || creature[which].species == CLOUD)
  1524.         {   effect(FXDEATH_FRAGMENT);
  1525.             creature[which].alive = FALSE;
  1526.         } elif (creature[which].species == ORB)
  1527.         {   for (player = 0; player <= 3; player++)
  1528.             {   letters[player][c - FIRSTLETTER] = FALSE;
  1529.                 drawletter(player, c, BLACK);
  1530.             }
  1531.             putletter(-1);
  1532.             orbscore(which, LETTERPOINT);
  1533.         } elif (creature[which].species == WHIRLWIND)
  1534.             putletter(-1);
  1535.     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  1536.     {   i = whichcreature(x, y, DRIP, which);
  1537.         if (creature[which].species == FRAGMENT)
  1538.             dripfrag(x, y, i, which);
  1539.         elif (creature[which].species == MISSILE)
  1540.             dripmissile(x, y, i, which);
  1541.         elif (creature[which].species == ORB)
  1542.             driporb(x, y, i, which);
  1543.         elif (creature[which].species == WHIRLWIND)
  1544.             dripwhirlwind(x, y, i, which);
  1545.         elif (creature[which].species == CLOUD)
  1546.             clouddrip(x, y, which, i);
  1547.     } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  1548.     {   i = whichcreature(x, y, MISSILE, which);
  1549.         if (creature[which].species == FRAGMENT)
  1550.             fragmissile(x, y, which, i);
  1551.         elif (creature[which].species == DRIP)
  1552.             dripmissile(x, y, which, i);
  1553.         elif (creature[which].species == ORB)
  1554.             orbmissile(x, y, which, i);
  1555.         elif (creature[which].species == WHIRLWIND)
  1556.             missilewhirlwind(x, y, i, which);
  1557.         elif (creature[which].species == MISSILE)
  1558.             missilemissile(x, y, which, i);
  1559.         elif (creature[which].species == CLOUD)
  1560.             cloudmissile(x, y, which, i);
  1561.     } elif (c == WHIRLWIND)
  1562.     {   i = whichcreature(x, y, WHIRLWIND, which);
  1563.         if (creature[which].species == DRIP)
  1564.             dripwhirlwind(x, y, which, i);
  1565.         elif (creature[which].species == MISSILE)
  1566.             missilewhirlwind(x, y, which, i);
  1567.         elif (creature[which].species == ORB)
  1568.             orbwhirlwind(x, y, which, i);
  1569.         elif (creature[which].species == WHIRLWIND)
  1570.             whirlwindwhirlwind(x, y, which, i);
  1571.         elif (creature[which].species == FRAGMENT)
  1572.             fragwhirlwind(x, y, which, i);
  1573.         elif (creature[which].species == CLOUD)
  1574.             cloudwhirlwind(x, y, which, i);
  1575.     } elif (c == DOG)
  1576.     {   i = whichcreature(x, y, DOG, which);
  1577.         if (creature[which].species == FRAGMENT)
  1578.             dogfrag(x, y, i, which);
  1579.         elif (creature[which].species == PENGUIN)
  1580.             dogpenguin(x, y, i, which);
  1581.         elif (creature[which].species == ORB)
  1582.             dogorb(x, y, i, which);
  1583.         elif (creature[i].species == DRIP)
  1584.             dogdrip(x, y, i, which);
  1585.         elif (creature[i].species == WHIRLWIND)
  1586.             dogwhirlwind(x, y, i, which);
  1587.         elif (creature[i].species == MISSILE)
  1588.             dogmissile(x, y, i, which);
  1589.         elif (creature[i].species == DOG)
  1590.             dogdog(x, y, i, which);
  1591.         elif (creature[i].species == CLOUD)
  1592.             clouddog(x, y, which, i);
  1593.     } elif (c == PENGUIN)
  1594.     {   i = whichcreature(x, y, PENGUIN, which);
  1595.         if (creature[which].species == ORB)
  1596.             orbpenguin(x, y, which, i);
  1597.         elif (creature[which].species == DOG)
  1598.             dogpenguin(x, y, which, i);
  1599.         elif (creature[which].species == WHIRLWIND)
  1600.             penguinwhirlwind(x, y, i, which);
  1601.         elif (creature[which].species == MISSILE)
  1602.             missilepenguin(x, y, which, i);
  1603.         elif (creature[which].species == DRIP)
  1604.             drippenguin(x, y, which, i);
  1605.         elif (creature[which].species == CLOUD)
  1606.             cloudpenguin(x, y, which, i);
  1607.         elif (creature[which].species == FRAGMENT)
  1608.             fragpenguin(x, y, which, i);
  1609.     } elif (c == FRAGMENT)
  1610.     {   i = whichcreature(x, y, FRAGMENT, which);
  1611.         if (creature[which].species == MISSILE)
  1612.             fragmissile(x, y, i, which);
  1613.         elif (creature[which].species == DRIP)
  1614.             dripfrag(x, y, which, i);
  1615.         elif (creature[which].species == ORB)
  1616.             fragorb(x, y, i, which);
  1617.         elif (creature[which].species == FRAGMENT)
  1618.             fragfrag(x, y, which, i);
  1619.         elif (creature[which].species == WHIRLWIND)
  1620.             fragwhirlwind(x, y, i, which);
  1621.         elif (creature[which].species == CLOUD)
  1622.             cloudfrag(x, y, which, i);
  1623.         elif (creature[which].species == DOG)
  1624.             dogfrag(x, y, which, i);
  1625.     } elif (c == METAL)
  1626.     {   if (creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD)
  1627.             creature[which].alive = FALSE;
  1628.         elif (creature[which].species == FRAGMENT)
  1629.             reflect(which);
  1630.     } elif (c == STONE)
  1631.     {   if (creature[which].species == DRIP || creature[which].species == FRAGMENT || creature[which].species == MISSILE || creature[which].species == CLOUD)
  1632.         {   effect(FXDEATH_FRAGMENT);
  1633.             creature[which].alive = FALSE;
  1634.     }   }
  1635.     elif (c == WOOD)
  1636.     {   if (creature[which].species == FRAGMENT || creature[which].species == MISSILE || creature[which].species == CLOUD || creature[which].species == DRIP)
  1637.         {   effect(FXDEATH_FRAGMENT);
  1638.             creature[which].alive = FALSE;
  1639.     }   }
  1640.     elif (c == GOAT)
  1641.     {   /* Drips, fragments, missiles, cyclones, dogs, clouds */
  1642.         creature[whichcreature(x, y, GOAT, which)].alive = FALSE;
  1643.         effect(FXDEATH_GOAT);
  1644.         if (creature[which].species != WHIRLWIND)
  1645.         {   creature[which].alive = FALSE;
  1646.             change(x, y, BONUS);
  1647.         }
  1648.         if (creature[which].species == MISSILE)
  1649.         {   wormscore(creature[which].type, KILLGOAT);
  1650.             if (worm[creature[which].type].bias)
  1651.             {   worm[creature[which].type].lives += GOATBLOOD;
  1652.                 stat(creature[which].type, LIFE);
  1653.     }   }   }
  1654.     elif (c == SLIME)
  1655.     {   if (creature[which].species == DRIP || creature[which].species == FRAGMENT || creature[which].species == MISSILE || (creature[which].species == ORB && creature[which].mode != ARMOUR))
  1656.         {   creature[which].alive = FALSE;
  1657.             change(x, y, EMPTY);
  1658.     }   }
  1659.     elif (c == DYNAMITE)
  1660.     {   if (creature[which].species == ORB)
  1661.         {   orbscore(which, DYNAMITEPOINT);
  1662.     }   }
  1663.     elif (c == SKULL)
  1664.     {   if (creature[which].species == ORB)
  1665.         {   effect(FXGET_SKULL);
  1666.             orbscore(which, SKULLPOINT);
  1667.         } elif (creature[which].species == FRAGMENT || creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD)
  1668.         {   effect(FXDEATH_FRAGMENT);
  1669.             creature[which].alive = FALSE;
  1670.     }   }
  1671.     elif (c == TELEPORT)
  1672.     {   /* Drips, fragments, missiles, orbs, whirlwinds, dogs, clouds */
  1673.         i = whichteleport(x, y);
  1674.         if (blocked(i, creature[which].deltax, creature[which].deltay))
  1675.             creature[which].alive = FALSE;
  1676.         else
  1677.         {   effect(FXUSE_TELEPORT);
  1678.             creature[which].x = teleport[level][partner(i)].x + creature[which].deltax;
  1679.             creature[which].y = teleport[level][partner(i)].y + creature[which].deltay;
  1680.  
  1681.             if (creature[which].species == ORB)
  1682.             {   orbscore(which, TELPOINT);
  1683.                 creature[which].x = xwrap(creature[which].x);
  1684.                 creature[which].y = ywrap(creature[which].y);
  1685.             } else
  1686.             {   if (!(valid(creature[which].x, creature[which].y)))
  1687.                     creature[which].alive = FALSE;
  1688.                 if (creature[which].species == FRAGMENT)
  1689.                     creature[which].last = SILVER;
  1690.     }   }   }
  1691.     elif (c == ORB)
  1692.     {   i = whichcreature(x, y, ORB, which);
  1693.         if (creature[which].species == DRIP)
  1694.             driporb(x, y, which, i);
  1695.         elif (creature[which].species == FRAGMENT)
  1696.             fragorb(x, y, which, i);
  1697.         elif (creature[which].species == WHIRLWIND)
  1698.             orbwhirlwind(x, y, i, which);
  1699.         elif (creature[which].species == PENGUIN)
  1700.             orbpenguin(x, y, i, which);
  1701.         elif (creature[which].species == MISSILE)
  1702.             orbmissile(x, y, i, which);
  1703.         elif (creature[which].species == DOG)
  1704.             dogorb(x, y, which, i);
  1705.         elif (creature[which].species == ORB)
  1706.             orborb(x, y, which, i);
  1707.         elif (creature[which].species == CLOUD)
  1708.             cloudorb(x, y, which, i);
  1709.     } elif (c == CLOUD)
  1710.     {   i = whichcreature(x, y, CLOUD, which);
  1711.         if (creature[which].species == DRIP)
  1712.             clouddrip(x, y, which, i);
  1713.         elif (creature[which].species == FRAGMENT)
  1714.             cloudfrag(x, y, which, i);
  1715.         elif (creature[which].species == WHIRLWIND)
  1716.             cloudwhirlwind(x, y, which, i);
  1717.         elif (creature[which].species == PENGUIN)
  1718.             cloudpenguin(x, y, which, i);
  1719.         elif (creature[which].species == MISSILE)
  1720.             cloudmissile(x, y, which, i);
  1721.         elif (creature[which].species == DOG)
  1722.             clouddog(x, y, which, i);
  1723.         elif (creature[which].species == ORB)
  1724.             cloudorb(x, y, which, i);
  1725.         elif (creature[which].species == CLOUD)
  1726.             cloudcloud(x, y, which, i);
  1727.     } elif (creature[which].species == ORB)
  1728.     {   if (c <= LASTOBJECT)
  1729.         {   orbscore(which, object[c].score);
  1730.             if (c == AMMO || c == PULSE || c == SLAYER || c == LIGHTNING)
  1731.             {   if (creature[which].mode != ARMOUR)
  1732.                     creature[which].explode = TRUE;
  1733.                 else effect(FXUSE_ARMOUR);
  1734.             } elif (c == NITRO || c == POWER || c == SLOWER || c == CYCLONE)
  1735.             {   effect(FXGET_NITRO);
  1736.                 creature[which].speed = speedup(creature[which].speed, TRUE);
  1737.             } elif (c == HEALER || c == LIFE || c == ICE || c == TREASURE || c == UMBRELLA || c == BONUS)
  1738.                 orbsplit(which);
  1739.             else switch (c)
  1740.             {
  1741.             case BOMB:
  1742.                 draw(x, y, ORB);
  1743.                 bombblast(ORB, which, x, y);
  1744.             break;
  1745.             case ARMOUR:
  1746.                 creature[which].armour += MODEADD + (rand() % MODERAND);
  1747.                 creature[which].mode = ARMOUR;
  1748.             break;
  1749.             case TONGUE:
  1750.                 creature[which].tongue += MODEADD + (rand() % MODERAND);
  1751.                 creature[which].mode = TONGUE;
  1752.             break;
  1753.             case PROTECTOR:
  1754.                 for (player = 0; player <= 3; player++)
  1755.                     if (worm[player].lives)
  1756.                         for (i = 0; i <= PROTECTORS; i++)
  1757.                            if (protector[player][i].alive)
  1758.                            {   protector[player][i].alive = FALSE;
  1759.                                if (protector[player][i].visible)
  1760.                                    change(protector[player][i].x, protector[player][i].y, EMPTY);
  1761.                            }
  1762.             break;
  1763.             case MISSILE:
  1764.             case CONVERTER:
  1765.                 effect(FXGET_OBJECT);
  1766.                 for (i = 0; i <= CREATURES; i++)
  1767.                 {   if (creature[i].alive && creature[i].species == MISSILE)
  1768.                     {   creature[i].alive = FALSE;
  1769.                         change(x, y, EMPTY);
  1770.                 }   }
  1771.             break;
  1772.             case MULTIPLIER:
  1773.                 effect(FXGET_OBJECT);
  1774.                 creature[which].multi *= 2;
  1775.                 if (creature[which].multi > MULTILIMIT)
  1776.                     creature[which].multi = MULTILIMIT;
  1777.             break;
  1778.             case BIAS:
  1779.                 effect(FXGET_OBJECT);
  1780.                 for (player = 0; player <= 3; player++)
  1781.                     if (worm[player].lives && worm[player].bias)
  1782.                     {   worm[player].bias = 0;
  1783.                         stat(player, BIAS);
  1784.                     }
  1785.             break;
  1786.             case AFFIXER:
  1787.                 effect(FXGET_OBJECT);
  1788.                 for (player = 0; player <= 3; player++)
  1789.                     if (worm[player].lives)
  1790.                     {   worm[player].affixer = FALSE;
  1791.                         icon(player, AFFIXER);
  1792.                     }
  1793.             break;
  1794.             case REMNANTS:
  1795.                 effect(FXGET_OBJECT);
  1796.                 for (player = 0; player <= 3; player++)
  1797.                     if (worm[player].lives)
  1798.                     {   worm[player].remnants = FALSE;
  1799.                         icon(player, REMNANTS);
  1800.                     }
  1801.             break;
  1802.             case SIDESHOT:
  1803.                 effect(FXGET_POWERUP);
  1804.                 for (player = 0; player <= 3; player++)
  1805.                     if (worm[player].lives)
  1806.                     {   worm[player].sideshot = FALSE;
  1807.                         icon(player, SIDESHOT);
  1808.                     }
  1809.             break;
  1810.             case MAGNET:
  1811.                 effect(FXGET_OBJECT);
  1812.                 for (i = 0; i <= MAGNETS; i++)
  1813.                     if (magnet[i].alive)
  1814.                         magnet[i].alive = FALSE;
  1815.             break;
  1816.             case PUSHER:
  1817.                 effect(FXGET_OBJECT);
  1818.                 for (i = 0; i <= 3; i++)
  1819.                     if (worm[i].lives && worm[i].pusher)
  1820.                     {   worm[i].pusher = FALSE;
  1821.                         icon(i, PUSHER);
  1822.                     }
  1823.             break;
  1824.             case FREEDOM:
  1825.                 effect(FXGET_OBJECT);
  1826.                 for (xx = 0; xx <= FIELDX; xx++)
  1827.                     for (yy = 0; yy <= FIELDY; yy++)
  1828.                         if (field[xx][yy] >= FIRSTFIRE && field[xx][yy] <= LASTFIRE)
  1829.                             change(xx, yy, EMPTY);
  1830.             break;
  1831.             case SWITCHER:
  1832.                 effect(FXGET_OBJECT);
  1833.                 for (xx = 0; xx <= FIELDX; xx++)
  1834.                     for (yy = 0; yy <= FIELDY; yy++)
  1835.                         if (field[xx][yy] >= FIRSTTAIL && field[xx][yy] <= LASTTAIL)
  1836.                             change(xx, yy, WOOD);
  1837.             break;
  1838.             case GROWER:
  1839.                 effect(FXGET_GROWER);
  1840.                 for (xx = 0; xx <= FIELDX; xx++)
  1841.                     for (yy = 0; yy <= FIELDY; yy++)
  1842.                         if (field[xx][yy] == WOOD)
  1843.                             for (xxx = xx - 1; xxx <= xx + 1; xxx++)
  1844.                                 for (yyy = yy - 1; yyy <= yy + 1; yyy++)                                                                if (valid(xxx, yyy) && field[xxx][yyy] == EMPTY)
  1845.                                     field[xxx][yyy] = TEMPWOOD;
  1846.                 for (xx = 0; xx <= FIELDX; xx++)
  1847.                     for (yy = 0; yy <= FIELDY; yy++)
  1848.                         if (field[xx][yy] == TEMPWOOD)
  1849.                             change(xx, yy, WOOD);
  1850.             break;
  1851.             case CLOCK:
  1852.                 secondsperlevel -= rand() % CLOCKRAND;
  1853.                 if (secondsperlevel < 0)
  1854.                     secondsperlevel = 0;
  1855.             break;
  1856.             case CUTTER:
  1857.                 for (i = 0; i <= 3; i++)
  1858.                     if (worm[i].lives && worm[i].cutter)
  1859.                     {   worm[i].cutter = 0;
  1860.                         icon(i, CUTTER);
  1861.                     }
  1862.             break;
  1863.             default:
  1864.                 // assert(0);
  1865.             break;
  1866.         }   }
  1867.         elif (c == EMPTY)
  1868.             orbscore(which, EMPTYPOINT);
  1869.         elif (c == SILVER)
  1870.             orbscore(which, SILVERPOINT);
  1871.         elif (c == GOLD)
  1872.             orbscore(which, GOLDPOINT);
  1873.     }   }
  1874.     
  1875.     x = creature[which].x; /* We refresh these in case a fragment has been */
  1876.     y = creature[which].y; /* reflected. Yes, it is vital. */
  1877.     
  1878.     if (creature[which].alive && creature[which].visible && (creature[which].deltax || creature[which].deltay))
  1879.     {   if (creature[which].species == MISSILE)
  1880.             change(x, y, FIRSTMISSILE + creature[which].type);
  1881.         elif (creature[which].species == DRIP)
  1882.             change(x, y, FIRSTDRIP + creature[which].type);
  1883.         elif (creature[which].species == ORB)
  1884.         {   field[x][y] = ORB;
  1885.             if (creature[which].mode == TONGUE)
  1886.                 draw(x, y, ORBTONGUE);
  1887.             elif (creature[which].mode == ARMOUR)
  1888.                 draw(x, y, ORBARMOUR);
  1889.             else draw(x, y, ORB);
  1890.         } else /* fragments, goats, penguins, cyclones, dogs, clouds */
  1891.         change(x, y, creature[which].species);
  1892.     }
  1893.     
  1894.     if (creature[which].alive)
  1895.     {   /* decide whether to fire */
  1896.         if (creature[which].species == GOAT)
  1897.         {   if (!(rand() % 10))
  1898.             {   for (i = 0; i <= CREATURES; i++)
  1899.                 {   if (!creature[i].alive)
  1900.                     {   creature[i].deltax = (rand() % 3) - 1;
  1901.                         creature[i].deltay = (rand() % 3) - 1;
  1902.                         if
  1903.                         (   valid(x + creature[i].deltax, y + creature[i].deltay)
  1904.                         &&  (creature[i].deltax || creature[i].deltay)
  1905.                         )
  1906.                         {   c = field[x + creature[i].deltax][y + creature[i].deltay];
  1907.                             if
  1908.                             (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1909.                             ||  (c >= FIRSTTAIL && c <= LASTTAIL)
  1910.                             )
  1911.                             {   effect(FXDO_GOAT);
  1912.                                 creature[i].alive = TRUE;
  1913.                                 creature[i].species = FRAGMENT;
  1914.                                 creature[i].x = x + creature[i].deltax;
  1915.                                 creature[i].y = y + creature[i].deltay;
  1916.                                 creature[i].visible = TRUE;
  1917.                                 creature[i].last = EMPTY;
  1918.                                 creature[i].speed = (SBYTE) atleast(FRAGSPEED - (level / 2), 1);
  1919.                         }   }
  1920.                         break;
  1921.         }   }   }   }
  1922.         elif (creature[which].species == CLOUD)
  1923.         {   if (!(rand() % 30))
  1924.             {   cloudbullet(which, x, y, -1);
  1925.                 cloudbullet(which, x, y, 1);
  1926.         }   }
  1927.         elif (creature[which].species == OCTOPUS)
  1928.         {   if (creature[which].dir == -1)
  1929.             {   if (!(rand() % 20))
  1930.                 {   creature[which].dir = 0;
  1931. }   }   }   }   }
  1932.  
  1933. MODULE void cloudbullet(UBYTE which, SBYTE x, SBYTE y, SBYTE deltay)
  1934. {   UBYTE i, c;
  1935.  
  1936.     for (i = 0; i <= CREATURES; i++)
  1937.     {   if (!creature[i].alive)
  1938.         {   creature[i].deltax = 0;
  1939.             creature[i].deltay = deltay;
  1940.             if (valid(x + creature[i].deltax, y + creature[i].deltay))
  1941.             {   c = field[x + creature[i].deltax][y + creature[i].deltay];
  1942.                 if
  1943.                 (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1944.                 ||  (c >= FIRSTTAIL && c <= LASTTAIL)
  1945.                 )
  1946.                 {   effect(FXDO_CLOUD);
  1947.                     creature[i].alive = TRUE;
  1948.                     creature[i].species = FRAGMENT;
  1949.                     creature[i].x = x;
  1950.                     creature[i].y = y + creature[i].deltay;
  1951.                     creature[i].visible = TRUE;
  1952.                     creature[i].last = EMPTY;
  1953.                     creature[i].speed = (SBYTE) atleast(FRAGSPEED - (level / 2), 1);
  1954.             }   }
  1955.             break;
  1956. }   }   }
  1957.  
  1958. MODULE void orbsplit(SBYTE which)
  1959. {   SBYTE   copy = 0, i;
  1960.  
  1961.     effect(FXDO_ORB);
  1962.     for (i = 0; i <= CREATURES; i++)
  1963.     {   if (!creature[i].alive)
  1964.         {   creature[i].x       = creature[which].x;
  1965.             creature[i].y       = creature[which].y;
  1966.             creature[i].score   = creature[which].score;
  1967.             creature[i].armour  = creature[which].armour;
  1968.             creature[i].tongue  = creature[which].tongue;
  1969.             creature[i].mode    = creature[which].mode;
  1970.             creature[i].speed   = creature[which].speed;
  1971.             creature[i].explode = FALSE;
  1972.             creature[i].multi   = creature[which].multi;
  1973.             creature[i].last    = EMPTY;
  1974.             creature[i].species = ORB;
  1975.             switch (copy)
  1976.             {
  1977.             case 0:
  1978.                 if (creature[which].deltax != -1 || creature[which].deltay != -1)
  1979.                 {   creature[i].deltax = -1;
  1980.                     creature[i].deltay = -1;
  1981.                     creature[i].alive = TRUE;
  1982.                 }
  1983.             break;
  1984.             case 1:
  1985.                 if (creature[which].deltax != 1 || creature[which].deltay != 1)
  1986.                 {   creature[i].deltax = 1;
  1987.                     creature[i].deltay = 1;
  1988.                     creature[i].alive = TRUE;
  1989.                 }
  1990.             break;
  1991.             case 2:
  1992.                 if (creature[which].deltax != 1 || creature[which].deltay != -1)
  1993.                 {   creature[i].deltax = 1;
  1994.                     creature[i].deltay = -1;
  1995.                     creature[i].alive = TRUE;
  1996.                 }
  1997.             break;
  1998.             case 3:
  1999.                 if (creature[which].deltax != -1 || creature[which].deltay != 1)
  2000.                 {   creature[i].deltax = -1;
  2001.                     creature[i].deltay = 1;
  2002.                     creature[i].alive = TRUE;
  2003.                 }
  2004.             break;
  2005.             default:
  2006.             break;
  2007.             }
  2008.             if (++copy >= 4)
  2009.                 return;
  2010. }   }   }
  2011.  
  2012. SBYTE partner(SBYTE which)
  2013. {   if (which % 2 == 0)
  2014.         return((SBYTE) (which + 1));
  2015.     else return((SBYTE) (which - 1));
  2016. }
  2017.  
  2018. /* NAME     putletter -- Put a letter onto the field
  2019. SYNOPSIS    void putletter(SBYTE player);
  2020. INPUTS      SBYTE player -
  2021.             0-3: player on whose behalf the letter is put on for
  2022.             -1: any letter
  2023. RESULT      none */
  2024.  
  2025. MODULE void putletter(SBYTE player)
  2026. {   ABOOL done;
  2027.     SBYTE i, x, y;
  2028.     UBYTE letter;
  2029.     SBYTE oldlettery = lettery;
  2030.  
  2031.     do
  2032.     {   done = findempty(&x, &y, FIRSTEMPTY, LASTEMPTY);
  2033.     } while (!done);
  2034.     if (player != -1)
  2035.     {   for (i = 0; i <= LETTERS; i++)
  2036.             if (!(letters[player][i]))
  2037.             {   break;
  2038.             }
  2039.         if (i > LETTERS) /* if no spare letters */
  2040.             letter = rand() % (LETTERS + 1);
  2041.         else
  2042.         {   do
  2043.                 letter = rand() % (LETTERS + 1);
  2044.             while (letters[player][letter]);
  2045.     }   }
  2046.     else letter = rand() % (LETTERS + 1);
  2047.     change(x, y, letter + FIRSTLETTER);
  2048.  
  2049.     letterx = x;
  2050.     lettery = y;
  2051.     lettertype = letter + FIRSTLETTER;
  2052.     updatearrow(oldlettery);
  2053.     updatearrow(lettery);
  2054. }
  2055.  
  2056. /* NAME     queue -- adds a keystroke to the key queue
  2057. SYNOPSIS    name(SBYTE, SBYTE, SBYTE);
  2058. FUNCTION    Adds a keystroke to the in-game key queue.
  2059. INPUTS      player - player that pressed the key
  2060.             deltax - the deltax of the key
  2061.             deltay - the deltay of the key
  2062. IMPLEMENTATION
  2063.             thewormqueue[] array has WORMQUEUELIMIT as its last index.
  2064.             It is implemented as a FIFO stack rather than LIFO so that
  2065.             the keystrokes are processed in the correct order (that is,
  2066.             the order in which they were pressed). The oldest keystroke
  2067.             is always at index [0], the next oldest at [1], and so on
  2068.             upwards to the newest keystroke, at [worm[player].pos].
  2069.             Keystrokes are removed from the bottom of the array ([0]),
  2070.             and the rest of the array is shuffled down to fill the gap,
  2071.             so that the contents of [1] go to [0], the contents of [2]
  2072.             go to [1], etc. worm[player].pos is adjusted to always point
  2073.             to the newest entry, which is the 'end' of the queue.
  2074. MODULE      engine.c */
  2075.  
  2076. void wormqueue(SBYTE player, SBYTE deltax, SBYTE deltay)
  2077. {       if (worm[player].pos < WORMQUEUELIMIT)
  2078.     {    worm[player].pos++;
  2079.         thewormqueue[player][worm[player].pos].deltax = deltax;
  2080.         thewormqueue[player][worm[player].pos].deltay = deltay;
  2081. }    }
  2082.  
  2083. MODULE void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay)
  2084. {   if (creature[which].pos < DOGQUEUELIMIT)
  2085.     {   creature[which].pos++;
  2086.         thedogqueue[which][creature[which].pos].deltax = deltax;
  2087.         thedogqueue[which][creature[which].pos].deltay = deltay;
  2088.     } else
  2089.     {   creature[which].alive = FALSE;
  2090.         change(creature[which].x, creature[which].y, EMPTY);
  2091. }   }
  2092.  
  2093. MODULE void reflect(UBYTE which)
  2094. {   creature[which].deltax  = -creature[which].deltax;
  2095.     creature[which].deltay  = -creature[which].deltay;
  2096.     creature[which].x      +=  creature[which].deltax * 2;
  2097.     creature[which].y      +=  creature[which].deltay * 2;
  2098. }
  2099.  
  2100. ABOOL savefields(STRPTR fieldname)
  2101. {   SBYTE i, j;
  2102.     TEXT  IOBuffer[NAMELENGTH + 1];
  2103.  
  2104.     matchteleports();
  2105.  
  2106.     if (!ZOpen(fieldname, TRUE))
  2107.         return FALSE;
  2108.  
  2109.     /* write header */
  2110.  
  2111.     strcpy(IOBuffer, "FSET 6.6");
  2112.     IOBuffer[9] = levels;
  2113.     if (!ZWrite(IOBuffer, 10))
  2114.     {   ZClose();
  2115.         return FALSE;
  2116.     }
  2117.  
  2118.     /* write high score table */
  2119.  
  2120.     for (i = 0; i <= HISCORES; i++)
  2121.     {   IOBuffer[0]                                             =  hiscore[i].player;
  2122.         IOBuffer[1]                                             =  hiscore[i].level;
  2123.  
  2124.         IOBuffer[2]                                             =   hiscore[i].score / 16777216;
  2125.         IOBuffer[3]                                             =  (hiscore[i].score % 16777216) / 65536;
  2126.         IOBuffer[4]                                             = ((hiscore[i].score % 16777216) % 65536) / 256;
  2127.         IOBuffer[5]                                             = ((hiscore[i].score % 16777216) % 65536) % 256;
  2128.         if (!ZWrite(IOBuffer, 6))
  2129.         {   ZClose();
  2130.             return FALSE;
  2131.         }
  2132.  
  2133.         for (j = 0; j <= NAMELENGTH; j++)
  2134.             IOBuffer[j]                                             = hiscore[i].name[j];
  2135.         if (!ZWrite(IOBuffer, NAMELENGTH + 1))
  2136.         {   ZClose();
  2137.             return FALSE;
  2138.         }
  2139.         for (j = 0; j <= TIMELENGTH; j++)
  2140.             IOBuffer[j]                                             = hiscore[i].time[j];
  2141.         if (!ZWrite(IOBuffer, TIMELENGTH + 1))
  2142.         {   ZClose();
  2143.             return FALSE;
  2144.         }
  2145.         for (j = 0; j <= DATELENGTH; j++)
  2146.             IOBuffer[j]                                             = hiscore[i].date[j];
  2147.         if (!ZWrite(IOBuffer, DATELENGTH + 1))
  2148.         {   ZClose();
  2149.             return FALSE;
  2150.     }   }
  2151.  
  2152.     /* write level data */
  2153.  
  2154.     for (i = 0; i <= levels; i++)
  2155.     {   IOBuffer[0]                        = startx[i];
  2156.         IOBuffer[1]                        = starty[i];
  2157.         IOBuffer[2]                                             = teleport[i][0].alive;
  2158.         IOBuffer[3]                                             = teleport[i][0].x;
  2159.         IOBuffer[4]                                             = teleport[i][0].y;
  2160.         IOBuffer[5]                                             = teleport[i][1].alive;
  2161.         IOBuffer[6]                                             = teleport[i][1].x;
  2162.         IOBuffer[7]                                             = teleport[i][1].y;
  2163.         if (!ZWrite(IOBuffer, 8))
  2164.         {   ZClose();
  2165.             return FALSE;
  2166.         }
  2167.  
  2168.         if (!ZWrite((char *) &board[i][0][0], LEVELSIZE))
  2169.         {   ZClose();
  2170.             return FALSE;
  2171.     }   }
  2172.  
  2173.     /* write version string */
  2174.  
  2175.     if (!ZWrite(VERSION, strlen(VERSION)))
  2176.     {   ZClose();
  2177.         return FALSE;
  2178.     }
  2179.  
  2180.     ZClose();
  2181.  
  2182.     if (clearthem)
  2183.         clearhiscores();
  2184.     modified = FALSE;
  2185.     return TRUE;
  2186. }
  2187.  
  2188. void saylevel(COLOUR colour)
  2189. {    TEXT mainstring[15] = "Level ", tempstring[4];
  2190.  
  2191.     if (level > 0)
  2192.     {    stci_d(&mainstring[6], level);
  2193.         strcat((char*) mainstring, " of ");
  2194.         stci_d(tempstring, levels);
  2195.         strcat((char*) mainstring, (char*) tempstring);
  2196.         say(mainstring, colour);
  2197.     } else
  2198.     {    if (a == FIELDEDIT)
  2199.             say("Bonus Level", colour);
  2200.         else
  2201.         {    if (leveltype == TREASURE)
  2202.                             say("Bonus Level: Treasury!", colour);
  2203.                         elif (leveltype == DRIP)
  2204.                             say("Bonus Level: Drips!", colour);
  2205.                         else
  2206.                         {   // assert(leveltype == PENGUIN);
  2207.                             say("Bonus Level: Penguins!", colour);
  2208. }       }       }       }
  2209.  
  2210. MODULE SBYTE slowdown(SBYTE speed, ABOOL nitro)
  2211. {   speed *= 2;
  2212.     if (nitro)
  2213.     {   if (speed > VERYSLOW)
  2214.             speed = VERYSLOW;
  2215.     } elif (speed > SLOW)
  2216.         speed = SLOW;
  2217.     return(speed);
  2218. }
  2219.  
  2220. MODULE void slowloop(void)
  2221. {   SBYTE i, player, which, x, xx, y, yy;
  2222.     UBYTE thissy;
  2223.  
  2224.     /* decrement worm strength */
  2225.  
  2226.     for (player = 0; player <= 3; player++)
  2227.         if (worm[player].lives > 0 && (ice == -1 || ice == player))
  2228.         {   if (worm[player].bias > 0)
  2229.             {   worm[player].bias--;
  2230.                 stat(player, BIAS);
  2231.             }
  2232.             if (worm[player].cutter > 0)
  2233.             {   worm[player].cutter--;
  2234.                 icon(player, CUTTER);
  2235.             }                
  2236.             if (worm[player].freedom > 0)
  2237.             {   worm[player].freedom--;
  2238.                 icon(player, FREEDOM);
  2239.             }
  2240.             if (worm[player].ice > 0)
  2241.             {   worm[player].ice--;
  2242.                 icon(player, ICE);
  2243.                 for (which = 0; which <= 3; which++)
  2244.                     if (player != which)
  2245.                         worm[which].pos = -1;
  2246.                 ice = -1;
  2247.                 icon(player, ICE);
  2248.             }
  2249.             if (worm[player].mode == ARMOUR)
  2250.             {   if (--worm[player].armour == 0)
  2251.                 {   if (worm[player].tongue > 0)
  2252.                         worm[player].mode = TONGUE;
  2253.                     else worm[player].mode = NOMODE;
  2254.                 }
  2255.                 stat(player, ARMOUR);
  2256.             } elif (worm[player].mode == TONGUE)
  2257.             {   if (--worm[player].tongue == 0)
  2258.                 {   if (worm[player].armour > 0)
  2259.                         worm[player].mode = ARMOUR;
  2260.                     else worm[player].mode = NOMODE;
  2261.                 }
  2262.                 stat(player, TONGUE);
  2263.         }   }
  2264.  
  2265.     /* blank out old causes */
  2266.  
  2267.     for (player = 0; player <= 3; player++)
  2268.     {   if (worm[player].lives > 0 && r > worm[player].causewait)
  2269.         {   drawcause(player, BLACK);
  2270.             worm[player].causewait = (ULONG) -1; /* most future time possible */
  2271.     }   }
  2272.  
  2273. if (ice == -1)
  2274. {   if (level)
  2275.     {    /* decrement orb strength */
  2276.         for (which = 0; which <= CREATURES; which++)
  2277.             if (creature[which].alive && creature[which].species == ORB)
  2278.                 if (creature[which].mode == ARMOUR)
  2279.                 {   if (--creature[which].armour == 0)
  2280.                         if (creature[which].tongue > 0)
  2281.                             creature[which].mode = TONGUE;
  2282.                         else creature[which].mode = NOMODE;
  2283.                 } elif (creature[which].mode == TONGUE)
  2284.                 {   if (--creature[which].tongue == 0)
  2285.                         if (creature[which].armour > 0)
  2286.                             creature[which].mode = ARMOUR;
  2287.                         else creature[which].mode = NOMODE;
  2288.                 }
  2289.  
  2290.         /* create goats */
  2291.         if
  2292.         (   (!(rand() % freq))
  2293.         &&  findempty(&x, &y, FIRSTGOAT, LASTGOAT)
  2294.         &&  field[x][y] != GOAT
  2295.         )
  2296.         {   for (i = 0; i <= CREATURES; i++)
  2297.             {   if (!creature[i].alive)
  2298.                 {   effect(FXBORN_GOAT);
  2299.                     creature[i].x = x;
  2300.                     creature[i].y = y;
  2301.                     creature[i].alive = TRUE;
  2302.                     creature[i].species = GOAT;
  2303.                     creature[i].last = creature[i].oldlast = field[x][y];
  2304.                     creature[i].speed = (SBYTE) atleast(GOATSPEED - (level / 2), 2);
  2305.                     creature[i].visible = TRUE;
  2306.                     change(x, y, GOAT);
  2307.                     break;
  2308.         }   }   }
  2309.  
  2310.         /* create octopi */
  2311.         if
  2312.         (   (!(rand() % (freq * 2)))
  2313.         &&  findempty(&x, &y, FIRSTGOAT, LASTGOAT)
  2314.         &&  field[x][y] != GOAT
  2315.         )
  2316.         {   for (i = 0; i <= CREATURES; i++)
  2317.             {   if (!creature[i].alive)
  2318.                 {   creature[i].x       = x;
  2319.                     creature[i].y       = y;
  2320.                     creature[i].alive   = TRUE;
  2321.                     creature[i].species = OCTOPUS;
  2322.                     creature[i].visible = TRUE;
  2323.                     creature[i].speed   = VERYSLOW;
  2324.                     creature[i].dir     = -1;
  2325.                     creature[i].deltax  = creature[i].deltay = 0;
  2326.                     change(x, y, OCTOPUS);
  2327.                     break;
  2328.         }   }   }
  2329.  
  2330.         /* create orbs */
  2331.         if
  2332.         (   (!(rand() % freq))
  2333.          && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY)
  2334.         )
  2335.         {   for (i = 0; i <= CREATURES; i++)
  2336.             {   if (!creature[i].alive)
  2337.                 {   effect(FXBORN_ORB);
  2338.                     creature[i].deltax = (rand() % 2) * 2 - 1;
  2339.                     creature[i].deltay = (rand() % 2) * 2 - 1;
  2340.                     creature[i].score = 0;
  2341.                     creature[i].alive = TRUE;
  2342.                     creature[i].armour = 0;
  2343.                     creature[i].tongue = 0;
  2344.                     creature[i].mode = NOMODE;
  2345.                     creature[i].speed = (SBYTE) atleast(ORBSPEED - (level / 2), 2);
  2346.                     creature[i].species = ORB;
  2347.                     creature[i].explode = FALSE;
  2348.                     creature[i].multi = 1;
  2349.                     creature[i].x = x;
  2350.                     creature[i].y = y;
  2351.                     creature[i].last = EMPTY;
  2352.                     creature[i].visible = TRUE;
  2353.                     change(x, y, ORB);
  2354.                     break;
  2355.         }   }   }
  2356.  
  2357.         /* create dogs */
  2358.         if ((!(rand() % freq)) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2359.         {   for (i = 0; i <= CREATURES; i++)
  2360.                 if (!(creature[i].alive))
  2361.                 {   creature[i].x = x;
  2362.                     creature[i].y = y;
  2363.                     creature[i].last = EMPTY;
  2364.                     creature[i].speed = (SBYTE) atleast(DOGSPEED - (level / 2), 2);
  2365.                     creature[i].visible = TRUE;
  2366.                     creature[i].deltax = 0;
  2367.                     creature[i].deltay = 0;
  2368.                     creature[i].species = DOG;
  2369.                     creature[i].alive = TRUE;
  2370.                     creature[i].pos = -1;
  2371.                     creature[i].dormant = DORMANT; /* dormant */
  2372.                     field[x][y] = DOG;
  2373.                     draw(x, y, DOGDORMANT);
  2374.                     break;
  2375.         }       }
  2376.  
  2377.         /* create slime */
  2378.         if ((!(rand() % (freq * 2))) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2379.             change(x, y, SLIME);
  2380.  
  2381.         /* grow slime */
  2382.         if (!(rand() % (freq * 2)))
  2383.         {   for (x = 0; x <= FIELDX; x++)
  2384.                 for (y = 0; y <= FIELDY; y++)
  2385.                     if (field[x][y] == SLIME)
  2386.                         for (xx = x - 1; xx <= x + 1; xx++)
  2387.                             for (yy = y - 1; yy <= y + 1; yy++)
  2388.                                 if (valid(xx, yy) && field[xx][yy] == EMPTY && !(rand() % 2))
  2389.                                     field[xx][yy] = TEMPSLIME;
  2390.             for (x = 0; x <= FIELDX; x++)
  2391.                 for (y = 0; y <= FIELDY; y++)
  2392.                     if (field[x][y] == TEMPSLIME)
  2393.                         change(x, y, SLIME);
  2394.         }
  2395.  
  2396.         /* create timebombs */
  2397.         if ((!(rand() % (freq * 8))) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2398.         {   for (i = 0; i <= CREATURES; i++)
  2399.             if (!(creature[i].alive))
  2400.             {   creature[i].x = x;
  2401.                 creature[i].y = y;
  2402.                 creature[i].last = EMPTY;
  2403.                 creature[i].speed = (SBYTE) atleast(TIMEBOMBSPEED - (level / 2), 2);
  2404.                 creature[i].visible = TRUE;
  2405.                 creature[i].deltax = 0;
  2406.                 creature[i].deltay = 0;
  2407.                 creature[i].species = TIMEBOMB;
  2408.                 creature[i].alive = TRUE;
  2409.                 creature[i].time = 10;
  2410.                 field[x][y] = TIMEBOMB;
  2411.                 draw(x, y, ZERO + 9);
  2412.                 break;
  2413.     }   }   }
  2414.  
  2415.     /* create drips */
  2416.     if
  2417.     (   (level && (!(rand() % freq)))
  2418.      || ((!level) && leveltype == DRIP && (!(rand() % FREQ_DRIP)))
  2419.     )
  2420.     {   x = (rand() % (FIELDX + 1));
  2421.         y = (rand() % 3);
  2422.         thissy = field[x][y];
  2423.         if (thissy >= FIRSTEMPTY && thissy <= LASTEMPTY)
  2424.         {   for (i = 0; i <= CREATURES; i++)
  2425.             {   if (!creature[i].alive)
  2426.                 {   effect(FXBORN_DRIP);
  2427.                     creature[i].alive      = TRUE;
  2428.                     creature[i].last       = EMPTY;
  2429.                     creature[i].species    = DRIP;
  2430.                     creature[i].type       = rand() % 4;
  2431.                     creature[i].x          = x;
  2432.                     creature[i].y          = y;
  2433.                     creature[i].deltax     = 0;
  2434.                     creature[i].deltay     = 1;
  2435.                     creature[i].visible    = TRUE;
  2436.                     if (level)
  2437.                         creature[i].speed  = (SBYTE) atleast(DRIPSPEED - (level / 2), 2);
  2438.                     else creature[i].speed = BONUSDRIPSPEED;
  2439.                     change(x, y, FIRSTDRIP + creature[i].type);
  2440.                     break;
  2441.     }   }   }   }
  2442.  
  2443.     /* create penguins */
  2444.     if
  2445.     ((   (  level  && !(rand() % freq))
  2446.      ||  ((!level) && leveltype == PENGUIN && (!(rand() % FREQ_PENGUIN)))
  2447.      ) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY)
  2448.     )
  2449.     {   for (i = 0; i <= CREATURES; i++)
  2450.             if (!(creature[i].alive))
  2451.             {   effect(FXBORN_PENGUIN);
  2452.                 creature[i].x = x;
  2453.                 creature[i].y = y;
  2454.                 creature[i].last = EMPTY;
  2455.                 if (level)
  2456.                     creature[i].speed = (SBYTE) atleast(PENGUINSPEED - (level / 2), 2);
  2457.                 else creature[i].speed = BONUSPENGUINSPEED;
  2458.                 creature[i].visible = TRUE;
  2459.                 creature[i].deltax = 0;
  2460.                 creature[i].deltay = 0;
  2461.                 creature[i].species = PENGUIN;
  2462.                 creature[i].alive = TRUE;
  2463.                 change(x, y, PENGUIN);
  2464.                 break;
  2465.     }       }
  2466.  
  2467.     /* create clouds */
  2468.     if (level && (!(rand() % freq)))
  2469.     {   x = (rand() % (FIELDX - 1)) + 1;
  2470.         y = (rand() % (FIELDY - 1)) + 1;
  2471.         /* If you create clouds at an extreme horizontal position
  2472.         (0 or FIELDX), will cause a crash because the deltas will be
  2473.         wrong. */
  2474.         thissy = field[x][y];
  2475.         if (thissy >= FIRSTEMPTY && thissy <= LASTEMPTY)
  2476.         {   for (i = 0; i <= CREATURES; i++)
  2477.             {   if (!creature[i].alive)
  2478.                 {   creature[i].alive       = TRUE;
  2479.                     creature[i].last        = EMPTY;
  2480.                     creature[i].species     = CLOUD;
  2481.                     creature[i].x           = x;
  2482.                     creature[i].y           = y;
  2483.                     if (x < FIELDX / 2)
  2484.                         creature[i].deltax  = 1;
  2485.                     else creature[i].deltax = -1;
  2486.                     creature[i].deltay      = 0;
  2487.                     creature[i].visible     = TRUE;
  2488.                     creature[i].speed       = (SBYTE) atleast(CLOUDSPEED - (level / 2), 3);
  2489.                     change(x, y, CLOUD);
  2490.                     break;
  2491.     }   }   }   }
  2492.  
  2493.     /* create objects */
  2494.     for (which = 0; which <= LASTOBJECT; which++)
  2495.         if (level || leveltype != TREASURE || which == TREASURE)
  2496.         {   if (!(rand() % object[which].freq) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2497.                 change(x, y, which);
  2498.         } elif (!(rand() % (object[which].freq / 10)) && findempty(&x, &y, FIRSTEMPTY, LASTEMPTY))
  2499.             change(x, y, which);
  2500.  
  2501.     /* create teleports */
  2502.     if (!(rand() % FREQ_TELEPORT)
  2503.     && !teleport[level][2].alive
  2504.     && findempty(&(teleport[level][2].x), &(teleport[level][2].y), FIRSTEMPTY, LASTEMPTY)
  2505.     && findempty(&(teleport[level][3].x), &(teleport[level][3].y), FIRSTEMPTY, LASTEMPTY)
  2506.     && (teleport[level][2].x != teleport[level][3].x || teleport[level][2].y != teleport[level][3].y))
  2507.     {   teleport[level][2].alive = TRUE;
  2508.         teleport[level][3].alive = TRUE;
  2509.         change(teleport[level][2].x, teleport[level][2].y, TELEPORT);
  2510.         change(teleport[level][3].x, teleport[level][3].y, TELEPORT);
  2511. }   }
  2512. }
  2513.  
  2514. MODULE SBYTE speedup(SBYTE speed, ABOOL nitro)
  2515. {    speed /= 2;
  2516.     if (speed < FAST)
  2517.         speed = FAST;
  2518.     return(speed);
  2519. }
  2520.  
  2521. MODULE ULONG squareblast(SBYTE type, SBYTE player, SBYTE thissy, SBYTE x, SBYTE y, ABOOL cutter)
  2522. {   SBYTE which;
  2523.     ULONG score = 0;
  2524.     SBYTE filler;
  2525.  
  2526.     if (type == HEAD && worm[player].bias)
  2527.         filler = SILVER;
  2528.     else filler = EMPTY;
  2529.  
  2530.     if (thissy <= LASTOBJECT)
  2531.     {   if (!cutter)
  2532.         {   change(x, y, filler);
  2533.     }   }
  2534.     elif (thissy >= FIRSTTAIL && thissy <= LASTTAIL)
  2535.     {   change(x, y, filler);
  2536.     } elif (thissy == ORB)
  2537.     {   which = whichcreature(x, y, ORB, 255);
  2538.         if (creature[which].mode != ARMOUR)
  2539.         {   effect(FXDEATH_ORB);
  2540.             creature[which].alive = FALSE;
  2541.             score = creature[which].score;
  2542.             if (type == HEAD && worm[player].bias)
  2543.                 worm[player].lives += ORBBLOOD;
  2544.             change(x, y, BONUS);
  2545.         } else effect(FXUSE_ARMOUR);
  2546.     } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  2547.     {   creature[whichcreature(x, y, DRIP, 255)].alive = FALSE;
  2548.         change(x, y, filler);
  2549.     } elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2550.     {   if (type != HEAD || player != thissy - FIRSTHEAD)
  2551.             if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2552.             {   worm[thissy - FIRSTHEAD].cause = BOMB;
  2553.                 worm[thissy - FIRSTHEAD].alive = FALSE;
  2554.                 stat(thissy - FIRSTHEAD, LIFE);
  2555.                 if (type == HEAD)
  2556.                     worm[thissy - FIRSTHEAD].victor = player;
  2557.                 else
  2558.                 {   worm[thissy - FIRSTHEAD].victor = -1;
  2559.                     score = KILLWORM; // worms will get this bonus from death(), so it is not given for them here.
  2560.             }   }
  2561.             else effect(FXUSE_ARMOUR);
  2562.     } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2563.     {   if (type != HEAD || player != thissy - FIRSTMISSILE)
  2564.         {   creature[whichcreature(x, y, MISSILE, 255)].alive = FALSE;
  2565.             change(x, y, filler);
  2566.     }    }
  2567.     elif (thissy == PENGUIN)
  2568.     {    creature[whichcreature(x, y, PENGUIN, 255)].alive = FALSE;
  2569.         change(x, y, filler);
  2570.     } elif (thissy == FRAGMENT)
  2571.     {    creature[whichcreature(x, y, FRAGMENT, 255)].alive = FALSE;
  2572.         change(x, y, filler);
  2573.     } elif (thissy == GOAT)
  2574.     {   creature[whichcreature(x, y, GOAT, 255)].alive = FALSE;
  2575.         change(x, y, BONUS);
  2576.     }
  2577.     return(score);
  2578. }
  2579.  
  2580. void timeloop(void)
  2581. {           TEXT  timedisplay[5] = {"#:##"};
  2582.     PERSIST ABOOL outoftime      = FALSE;
  2583.             UBYTE i;
  2584.  
  2585.     secondsleft = atleast(secondsleft, 0);
  2586.     timedisplay[0] = 48 +  (secondsleft / 60);
  2587.     timedisplay[2] = 48 + ((secondsleft % 60) / 10);
  2588.     timedisplay[3] = 48 + ((secondsleft % 60) % 10);
  2589.  
  2590.     if (!level)
  2591.     {   say(timedisplay, worm[treasurer].colour);
  2592.         if (!secondsleft)
  2593.         {   level = reallevel + 1;
  2594.             secondsleft = SECONDSPERLEVEL;
  2595.             newlevel(treasurer);
  2596.     }   }
  2597.     elif (!secondsleft)
  2598.     {   if (!outoftime)
  2599.         {   effect(FXSIREN);
  2600.             say("Out of time!", WHITE);
  2601.             outoftime = TRUE;
  2602.             freq /= 2;
  2603.             for (i = 0; i <= CREATURES; i++)
  2604.                 if (creature[i].alive)
  2605.                     creature[i].speed = speedup(creature[i].speed, TRUE);
  2606.     }   }
  2607.     else
  2608.     {    outoftime = FALSE;
  2609.         say(timedisplay, WHITE);
  2610. }    }
  2611.  
  2612. void train(SCANCODE scancode)
  2613. {   SBYTE i, x, y;
  2614.  
  2615.     switch(scancode)
  2616.     {
  2617.     case HELP:
  2618.         trainer = !trainer;
  2619.     break;
  2620.     case NUMERICSLASH:
  2621.         /* Complete the level. */
  2622.         if (trainer)
  2623.         {   trainer = FALSE;
  2624.             if (worm[1].lives > 0)
  2625.             for (i = 0; i <= LETTERS; i++)
  2626.             {   letters[1][i] = TRUE;
  2627.                 drawletter(1, FIRSTLETTER + i, NORMAL);
  2628.         }   }
  2629.     break;
  2630.     case NUMERICASTERISK:
  2631.         /* field[][] dump, for debugging purposes. */
  2632.         if (trainer)
  2633.         {   trainer = FALSE;
  2634.             say("Field dump...", PURPLE);
  2635.             for (x = 0; x <= FIELDX; x++)
  2636.                 for (y = 0; y <= FIELDY; y++)
  2637.                     draw(x, y, field[x][y]);
  2638.             anykey(FALSE);
  2639.         }
  2640.         break;
  2641.     case NUMERICPLUS:
  2642.         if (trainer)
  2643.         {   trainer = FALSE;
  2644.             say("Trainer activated!", PURPLE);
  2645.             anykey(FALSE);
  2646.             if (worm[1].lives > 0)
  2647.             {   worm[1].lives = LIVESLIMIT;
  2648.                 stat(1, LIFE);
  2649.                 worm[1].tongue = MODELIMIT;
  2650.                 worm[1].mode = TONGUE;
  2651.                 stat(1, TONGUE);
  2652.                 worm[1].bias = BIASLIMIT;
  2653.                 stat(1, BIAS);
  2654.                 worm[1].ammo = AMMOLIMIT;
  2655.                 stat(1, AMMO);
  2656.                 worm[1].power = POWERLIMIT;
  2657.                 stat(1, POWER);
  2658.                 worm[1].nitro = TRUE;
  2659.                 stat(1, NITRO);
  2660.                 worm[1].affixer = TRUE;
  2661.                 icon(1, AFFIXER);
  2662.                 worm[1].remnants = TRUE;
  2663.                 icon(1, REMNANTS);
  2664.                 worm[1].sideshot = TRUE;
  2665.                 icon(1, SIDESHOT);
  2666.                 worm[1].pusher = TRUE;
  2667.                 icon(1, PUSHER);
  2668.                 worm[1].cutter = 100;
  2669.                 icon(1, CUTTER);
  2670.                 trainer = FALSE;
  2671.         }   }
  2672.     break;
  2673.     default:
  2674.     break;
  2675. }   }
  2676.  
  2677. MODULE void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
  2678. {
  2679. if (worm[player].nitro || !deltax || !deltay)
  2680. {    if (worm[player].deltax == deltax && worm[player].deltay == deltay)
  2681.     {    worm[player].speed = speedup(worm[player].speed, worm[player].nitro);
  2682.         stat(player, NITRO);
  2683.     } elif (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
  2684.         {       worm[player].speed = slowdown(worm[player].speed, worm[player].nitro);
  2685.         stat(player, NITRO);
  2686.     } else
  2687.     {    worm[player].deltax = deltax;
  2688.         worm[player].deltay = deltay;
  2689. }    }
  2690. }
  2691.  
  2692. SBYTE valid(SBYTE x, SBYTE y)
  2693. {   if (x >= 0 && x <= FIELDX && y >= 0 && y <= FIELDY)
  2694.         return(TRUE);
  2695.     else return(FALSE);
  2696. }
  2697.  
  2698. MODULE UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception)
  2699. {   UBYTE i;    
  2700.  
  2701.     for (i = 0; i <= CREATURES; i++)
  2702.         if
  2703.         (   creature[i].alive
  2704.          && creature[i].x == x
  2705.          && creature[i].y == y
  2706.          && creature[i].species == species
  2707.          && i != exception
  2708.         )
  2709.             return i;
  2710.     return 255; /* error code */
  2711. }
  2712. MODULE SBYTE whichteleport(SBYTE x, SBYTE y)
  2713. {   SBYTE which;
  2714.  
  2715.     for (which = 0; which <= 3; which++)
  2716.         if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
  2717.             return((SBYTE) which);
  2718.     return((SBYTE) -1); /* error code */
  2719. }
  2720.  
  2721. MODULE void wormbullet(SBYTE player)
  2722. {   ABOOL   finished,
  2723.             flag            = FALSE,
  2724.             ok              = FALSE,
  2725.             lettered        = FALSE;
  2726.     LONG    score;
  2727.     SBYTE   distance,
  2728.             thissy,
  2729.             i, j,
  2730.             x, y;
  2731.  
  2732.     if (!worm[player].ammo)
  2733.     {   stat(player, BONUS);
  2734.     if (worm[player].speed == FAST)
  2735.         distance = FASTDISTANCE;
  2736.     elif (worm[player].speed == NORMAL)
  2737.        distance = NORMALDISTANCE;
  2738.         elif (worm[player].speed == SLOW)
  2739.        distance = SLOWDISTANCE;
  2740.         else
  2741.         {  // assert(worm[player].speed == VERYSLOW);
  2742.            distance = VERYSLOWDISTANCE;
  2743.         }
  2744.  
  2745.     /* check for metal */
  2746.  
  2747.     for (i = 1; i < distance; i++)
  2748.     {   x = xwrap(worm[player].x + (i * worm[player].deltax));
  2749.         y = ywrap(worm[player].y + (i * worm[player].deltay));
  2750.         if (field[x][y] == METAL)
  2751.         flag = TRUE;
  2752.     }
  2753.  
  2754.     if (!flag)
  2755.         {   // assert(abs(worm[player].deltax) <= 1 && abs(worm[player].deltay) <= 1);
  2756.         x = xwrap(worm[player].x + (worm[player].deltax * distance));
  2757.         y = ywrap(worm[player].y + (worm[player].deltay * distance));
  2758.         thissy = field[x][y];
  2759.         if (thissy == TELEPORT)
  2760.         {   i = whichteleport(x, y);
  2761.             if (!blocked(i, worm[player].deltax, worm[player].deltay))
  2762.             ok = TRUE;
  2763.         }
  2764.             if (ok || ((thissy < STONE || thissy > GOAT) && thissy != METAL))
  2765.             {   effect(FXDO_JUMP);
  2766.             worm[player].deltax *= distance;
  2767.             worm[player].deltay *= distance;
  2768.     }   }   }
  2769.     else
  2770.     {   effect(FXUSE_AMMO);
  2771.         worm[player].ammo--;
  2772.         stat(player, AMMO);
  2773.         if (worm[player].bias)
  2774.             createmissile(player, worm[player].x, worm[player].y);
  2775.  
  2776.         if (worm[player].sideshot)
  2777.         {   bullet[7].alive      = bullet[8].alive      = TRUE;
  2778.             bullet[7].teleported = bullet[8].teleported = 0;
  2779.             bullet[7].visible    = bullet[8].visible    = TRUE;
  2780.             bullet[7].reflected  = bullet[8].reflected  = FALSE;
  2781.             bullet[7].x          = bullet[8].x          = worm[player].x;
  2782.             bullet[7].y          = bullet[8].y          = worm[player].y;
  2783.             if (!worm[player].deltax && worm[player].deltay)
  2784.             {   bullet[7].deltax = -1;
  2785.                 bullet[8].deltax = 1;
  2786.                 bullet[7].deltay = bullet[8].deltay = 0;
  2787.             } elif (worm[player].deltax && !worm[player].deltay)
  2788.             {   bullet[7].deltax = bullet[8].deltax = 0;
  2789.                 bullet[7].deltay = -1;
  2790.                 bullet[8].deltay = 1;
  2791.             } else /* worm is diagonal */
  2792.             {   if (worm[player].deltax == worm[player].deltay)
  2793.                 {   bullet[7].deltax = 1;
  2794.                     bullet[7].deltay = -1;
  2795.                 } else
  2796.                 {   bullet[7].deltax = -1;
  2797.                     bullet[7].deltay = -1;
  2798.                 }
  2799.                 bullet[8].deltax = -bullet[7].deltax;
  2800.                 bullet[8].deltay = -bullet[7].deltay;
  2801.         }   }
  2802.  
  2803.         for (i = 0; i <= worm[player].power; i++)
  2804.         {   bullet[i].alive      = TRUE;
  2805.             bullet[i].teleported = 0;
  2806.             bullet[i].visible    = TRUE;
  2807.             bullet[i].reflected  = FALSE;
  2808.             bullet[i].deltax     = worm[player].deltax;
  2809.             bullet[i].deltay     = worm[player].deltay;
  2810.             if (i % 2 == 0)
  2811.                 distance = i / 2;
  2812.             else distance = -((i + 1) / 2);
  2813.             if (worm[player].deltax == 0)
  2814.             {   bullet[i].x = worm[player].x + distance;
  2815.                 bullet[i].y = worm[player].y;
  2816.             } elif (worm[player].deltay == 0)
  2817.             {   bullet[i].x = worm[player].x;
  2818.                 bullet[i].y = worm[player].y + distance;
  2819.             } else
  2820.             {   switch (i)
  2821.                 {
  2822.                 case 0:
  2823.                     bullet[i].x = worm[player].x + worm[player].deltax;
  2824.                     bullet[i].y = worm[player].y + worm[player].deltay;
  2825.                 break;
  2826.                 case 1:
  2827.                     bullet[i].x = worm[player].x + worm[player].deltax;
  2828.                     bullet[i].y = worm[player].y;
  2829.                 break;
  2830.                 case 2:
  2831.                     bullet[i].x = worm[player].x;
  2832.                     bullet[i].y = worm[player].y + worm[player].deltay;
  2833.                 break;
  2834.                 case 3:
  2835.                     bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2836.                     bullet[i].y = worm[player].y;
  2837.                 break;
  2838.                 case 4:
  2839.                     bullet[i].x = worm[player].x;
  2840.                     bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2841.                 break;
  2842.                 case 5:
  2843.                     bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2844.                     bullet[i].y = worm[player].y - worm[player].deltay;
  2845.                 break;
  2846.                 case 6:
  2847.                     bullet[i].x = worm[player].x - worm[player].deltax;
  2848.                     bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2849.                 break;
  2850.                 default:
  2851.                 break;
  2852.         }   }   }
  2853.  
  2854.         /* Bullets are now set up. */
  2855.  
  2856.         score = 0;
  2857.         finished = FALSE;
  2858.         while (!finished)
  2859.         {   finished = TRUE;
  2860.             for (i = 0; i <= 8; i++)
  2861.             {   if (bullet[i].alive)
  2862.                 {   finished = FALSE;
  2863.                     if (bullet[i].reflected)
  2864.                     {   bullet[i].x -= bullet[i].deltax;
  2865.                         bullet[i].y -= bullet[i].deltay;
  2866.                     } else
  2867.                     {   bullet[i].x += bullet[i].deltax;
  2868.                         bullet[i].y += bullet[i].deltay;
  2869.                     }
  2870.                     x = bullet[i].x;
  2871.                     y = bullet[i].y;
  2872.                     thissy = field[x][y];
  2873.                     if (!(valid(x, y)))
  2874.                         bullet[i].alive = FALSE;
  2875.                     elif (x == worm[player].x && y == worm[player].y)
  2876.                     {   /* hit by own bullet */
  2877.                         bullet[i].alive = FALSE;
  2878.                         if (worm[player].mode != ARMOUR)
  2879.                         {   worm[player].cause = FIRSTFIRE + player;
  2880.                             worm[player].victor = -1;
  2881.                             worm[player].alive = FALSE;
  2882.                     }   }
  2883.                     elif (thissy >= FIRSTHEAD && thissy <= LASTHEAD)
  2884.                     {   if (worm[thissy - FIRSTHEAD].mode != ARMOUR)
  2885.                         {   worm[thissy - FIRSTHEAD].cause = FIRSTFIRE + player;
  2886.                             worm[thissy - FIRSTHEAD].victor = player;
  2887.                             worm[thissy - FIRSTHEAD].alive = FALSE;
  2888.                             if (player != thissy - FIRSTHEAD)
  2889.                                 score += KILLWORM + HITSHOT;
  2890.                         } else effect(FXUSE_ARMOUR);
  2891.                         bullet[i].alive = FALSE;
  2892.                     } elif (thissy >= FIRSTPROTECTOR && thissy <= LASTPROTECTOR)
  2893.                     {   if (player != thissy - FIRSTPROTECTOR)
  2894.                         {   effect(FXUSE_PROTECTOR);
  2895.                             bullet[i].alive = FALSE;
  2896.                         } else bullet[i].visible = FALSE;
  2897.                     } elif (thissy >= FIRSTMISSILE && thissy <= LASTMISSILE)
  2898.                     {   if (player != thissy - FIRSTMISSILE)
  2899.                             creature[whichcreature(x, y, MISSILE, 255)].alive = FALSE;
  2900.                         else bullet[i].visible = FALSE;
  2901.                     } elif (thissy >= FIRSTDRIP && thissy <= LASTDRIP)
  2902.                     {   j = whichcreature(x, y, DRIP, 255);
  2903.                         creature[j].alive = FALSE;
  2904.                     } elif (thissy >= FIRSTLETTER && thissy <= LASTLETTER)
  2905.                     {   wormletter(player, thissy);
  2906.                         lettered = TRUE;
  2907.                     } else
  2908.                     {   switch(thissy)
  2909.                         {
  2910.                         case METAL:
  2911.                             if (bullet[i].reflected)
  2912.                                 bullet[i].alive = FALSE;
  2913.                             else
  2914.                             {   bullet[i].reflected = TRUE;
  2915.                                 bullet[i].x -= bullet[i].deltax * 2;
  2916.                                 bullet[i].y -= bullet[i].deltay * 2;
  2917.                             }
  2918.                             break;
  2919.                         case STONE:
  2920.                         case WHIRLWIND:
  2921.                             bullet[i].alive = FALSE;
  2922.                         break;
  2923.                         case ORB:
  2924.                             bullet[i].alive = FALSE;
  2925.                             j = whichcreature(x, y, ORB, 255);
  2926.                             if (creature[j].mode != ARMOUR)
  2927.                             {   creature[j].explode = TRUE;
  2928.                                 score += creature[j].score + HITSHOT;
  2929.                                 if (worm[player].bias)
  2930.                                     worm[player].lives += ORBBLOOD;
  2931.                             } else effect(FXUSE_ARMOUR);
  2932.                         break;
  2933.                         case TELEPORT:
  2934.                             j = whichteleport(bullet[i].x, bullet[i].y);
  2935.                             if (bullet[i].teleported == 2)
  2936.                                 bullet[i].alive = FALSE;
  2937.                             else
  2938.                             {   effect(FXUSE_TELEPORT);
  2939.                                 bullet[i].visible = FALSE;
  2940.                                 bullet[i].teleported++;
  2941.                                 bullet[i].x = teleport[level][partner(j)].x;
  2942.                                 bullet[i].y = teleport[level][partner(j)].y;
  2943.                                 score += TELPOINT;
  2944.                             }
  2945.                         break;
  2946.                         case WOOD:
  2947.                             if (!worm[player].bias)
  2948.                                 bullet[i].alive = FALSE;
  2949.                         break;
  2950.                         case OCTOPUS:
  2951.                             creature[whichcreature(x, y, OCTOPUS, 255)].alive = FALSE;
  2952.                             change(x, y, BONUS);
  2953.                             score += KILLOCTOPUS + HITSHOT;
  2954.                             if (worm[player].bias)
  2955.                             {   worm[player].lives += OCTOPUSBLOOD;
  2956.                             }
  2957.                             bullet[i].alive = FALSE;
  2958.                         break;
  2959.                         case GOAT:
  2960.                             effect(FXDEATH_GOAT);
  2961.                             creature[whichcreature(x, y, GOAT, 255)].alive = FALSE;
  2962.                             change(x, y, BONUS);
  2963.                             score += KILLGOAT + HITSHOT;
  2964.                             if (worm[player].bias)
  2965.                             {   worm[player].lives += GOATBLOOD;
  2966.                             }
  2967.                             bullet[i].alive = FALSE;
  2968.                         break;
  2969.                         case SKULL:
  2970.                             bullet[i].alive = FALSE;
  2971.                         break;
  2972.                         case FRAGMENT:
  2973.                             bullet[i].alive = FALSE;
  2974.                             creature[whichcreature(x, y, FRAGMENT, 255)].alive = FALSE;
  2975.                             change(x, y, EMPTY);
  2976.                         break;
  2977.                         case PENGUIN:
  2978.                             bullet[i].alive = FALSE;
  2979.                             creature[whichcreature(x, y, PENGUIN, 255)].alive = FALSE;
  2980.                             change(x, y, EMPTY);
  2981.                             score += KILLPENGUIN + HITSHOT;
  2982.                             if (worm[player].bias)
  2983.                                 worm[player].lives += PENGUINBLOOD;
  2984.                         break;
  2985.                         case DOG:
  2986.                             bullet[i].alive = FALSE;
  2987.                         break;
  2988.                         case CLOUD:
  2989.                             creature[whichcreature(x, y, CLOUD, 255)].alive = FALSE;
  2990.                             change(x, y, EMPTY);
  2991.                         break;
  2992.                         case TIMEBOMB:
  2993.                             creature[whichcreature(x, y, TIMEBOMB, 255)].alive = FALSE;
  2994.                             bombblast(BOMB, 0, x, y);
  2995.                             change(x, y, EMPTY);
  2996.                         break;
  2997.                         default:
  2998.                         break;
  2999.                     }   }
  3000.  
  3001.                     // x and y need this refreshing here
  3002.                     x = bullet[i].x;
  3003.                     y = bullet[i].y;
  3004.                     if (bullet[i].alive && bullet[i].visible)
  3005.                     {   draw(x, y, FIRSTFIRE + player);
  3006.                         if (worm[player].remnants)
  3007.                             field[x][y] = FIRSTFIRE + player;
  3008.                         elif (bullet[i].teleported)
  3009.                             change(x, y, GOLD);
  3010.                         else change(x, y, EMPTY);
  3011.         }   }   }   }
  3012.         if (lettered)
  3013.             putletter(player);
  3014.         wormscore(player, score);
  3015.         if (worm[player].bias)
  3016.             stat(player, LIFE);
  3017.         clearkybd();
  3018. }   }
  3019.  
  3020. MODULE void wormletter(SBYTE player, SBYTE c)
  3021. {   switch(c)
  3022.     {
  3023.     case GREEN_C:
  3024.         effect(FX_C);
  3025.     break;
  3026.     case RED_O:
  3027.         effect(FX_O);
  3028.     break;
  3029.     case BLUE_M:
  3030.         effect(FX_M);
  3031.     break;
  3032.     case YELLOW_P:
  3033.        effect(FX_P);
  3034.     break;
  3035.     case GREEN_L:
  3036.         effect(FX_L);
  3037.     break;
  3038.     case BLUE_T:
  3039.         effect(FX_T);
  3040.     break;
  3041.     default:
  3042.         // assert(c == RED_E || c == YELLOW_E);
  3043.         effect(FX_E);
  3044.     break;
  3045.     }
  3046.     letters[player][c - FIRSTLETTER] = TRUE;
  3047.     drawletter(player, c, NORMAL);
  3048.     wormscore(player, LETTERPOINT);
  3049. }
  3050.  
  3051. /* NAME     wormloop -- controls worms and protectors
  3052. SYNOPSIS    wormloop(SBYTE);
  3053. FUNCTION    Amiga-worm thinking, processing one keystroke from the
  3054.             worm's queue, all the worm's protectors' control, the
  3055.             worm's control.
  3056. MODULE      engine.c */
  3057.  
  3058. MODULE void wormloop(SBYTE player)
  3059. {   AUTO    ABOOL enclosed = FALSE, ok;
  3060.     AUTO    SBYTE bestx = 0, besty = 0, // to avoid spurious warnings
  3061.                   c, d, dirx, diry, i, k, thisprot, x, y,
  3062.                   leftx, rightx, topy, bottomy;
  3063.     AUTO    SWORD bestgood, good;
  3064.     AUTO    UBYTE interior;
  3065.     AUTO    ULONG score = 0;
  3066.     PERSIST struct
  3067.     {   SBYTE deltax[4], deltay[4];
  3068.     } deltas[4] =
  3069.     { { { 0, -1,  0,  1}, // northwest
  3070.         {-1,  0,  1,  0}
  3071.       },
  3072.       { { 0,  1,  0, -1}, // northeast
  3073.         {-1,  0,  1,  0}
  3074.       },
  3075.       { { 0,  1,  0, -1}, // southeast
  3076.         { 1,  0, -1,  0}
  3077.       },
  3078.       { { 0, -1,  0,  1}, // southwest
  3079.         { 1,  0, -1,  0}
  3080.     } };
  3081.     PERSIST struct
  3082.     {   SBYTE leftx, rightx, topy, bottomy;
  3083.     } enclose[4] =
  3084.     { {-127,   -1, -127,  -1 }, // northwest
  3085.       {   1,  127, -127,  -1 }, // northeast
  3086.       {   1,  127,    1, 127 }, // southeast
  3087.       {-127,   -1,    1, 127 }  // southwest
  3088.     };
  3089.  
  3090.    /*  Amiga worm control
  3091.        Remove a keystroke from the worm queue
  3092.        Move worm (and add a keystroke to the dog queue)
  3093.        Check for enclosure
  3094.        Move protectors
  3095.        Collision detection
  3096.  
  3097.     AI: Amiga worm control.
  3098.  
  3099.     Worm checks ahead, left and right one square. Assigns opinions
  3100.     to those three choices and then takes the appropriate one. */
  3101.  
  3102.     if (worm[player].control == AMIGA)
  3103.     {   if (!(rand() % 50))
  3104.             wormqueue(player, (rand() % 3) - 1, (rand() % 3) - 1);
  3105.         else
  3106.         {   bestgood = -128;
  3107.  
  3108.             for (i = 0; i <= 2; i++)
  3109.             {   switch(i)
  3110.                 {
  3111.                 case 0:
  3112.                     dirx = worm[player].deltax;
  3113.                     diry = worm[player].deltay;
  3114.                 break;
  3115.                 case 1:
  3116.                     if (worm[player].deltax == 0) /* if going north or south */
  3117.                     {   dirx = -1;                /* then look west */
  3118.                         diry = 0;
  3119.                     } else                        /* if going east or west */
  3120.                     {   dirx = 0;                 /* then look north */
  3121.                         diry = -1;
  3122.                     }
  3123.                 break;
  3124.                 case 2:
  3125.                     if (worm[player].deltax == 0) /* if going north or south */
  3126.                     {   dirx = 1;                 /* then look east */
  3127.                         diry = 0;
  3128.                     } else                        /* if going east or west */
  3129.                     {   dirx = 0;                 /* then look south */
  3130.                         diry = 1;
  3131.                     }
  3132.                 break;
  3133.                 default:
  3134.                     dirx = diry = 0; // to prevent spurious warnings
  3135.                 break;
  3136.                 }
  3137.                 c = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
  3138.                 if (c >= FIRSTLETTER && c <= LASTLETTER)
  3139.                     good = LETTERPOINT;
  3140.                 elif (c >= FIRSTHEAD && c <= LASTHEAD)
  3141.                     good = -55;
  3142.                 elif (c <= LASTOBJECT)
  3143.                     good = (SWORD) object[c].score;
  3144.                 elif (c == FIRSTPROTECTOR + player)
  3145.                     good = 6;
  3146.                 elif (c == FIRSTFIRE && c <= LASTFIRE)
  3147.         {   if (player == c - FIRSTFIRE)
  3148.                 good = -1;
  3149.                     else good = -70;
  3150.                 } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  3151.                 {   if (worm[player].mode == TONGUE && worm[player].tongue > 10)
  3152.                         if (player != c - FIRSTTAIL)
  3153.                             good = 10;
  3154.                         else good = -10;
  3155.                     elif (player == c - FIRSTTAIL)
  3156.                         good = -30;
  3157.                     else good = -60;
  3158.                 } else switch(c)
  3159.                 {
  3160.                 case SKULL:
  3161.                     good = 70;
  3162.                 break;
  3163.                 case GOLD:
  3164.                     good = GOLDPOINT;
  3165.                 break;
  3166.                 case SILVER:
  3167.                     good = SILVERPOINT;
  3168.                 break;
  3169.                 case EMPTY:
  3170.                     good = EMPTYPOINT;
  3171.                 break;
  3172.                 case SLIME:
  3173.                     if (worm[player].mode == ARMOUR)
  3174.                         good = -2;
  3175.                     else good = -75;
  3176.                 break;
  3177.                 case WOOD:
  3178.                     if (worm[player].mode == ARMOUR)
  3179.                         good = -2;
  3180.                     else good = -70;
  3181.                 break;
  3182.                 case STONE:
  3183.                     good = -85;
  3184.                 break;
  3185.                 case METAL:
  3186.                     good = -90;
  3187.                 break;
  3188.                 case GOAT:
  3189.                     good = -95;
  3190.                 break;
  3191.                 case WHIRLWIND:
  3192.                     good = -100;
  3193.                 break;
  3194.                 case ORB:
  3195.                     good = -45;
  3196.                 break;
  3197.                 case CLOUD:
  3198.                     good = -40;
  3199.                 break;
  3200.                 default:
  3201.                     good = -50;
  3202.                 break;
  3203.                 }
  3204.                 if (good > bestgood)
  3205.                 {   bestx = dirx;
  3206.                     besty = diry;
  3207.                     bestgood = good;
  3208.             }   }
  3209.             if (bestgood <= -80)
  3210.             {   // turn to the right
  3211.                 if (worm[player].deltax == 0) /* if going north or south */
  3212.                 {   bestx = 1;                /* then turn east */
  3213.                     besty = 0;
  3214.                 } else                        /* if going east or west */
  3215.                 {   bestx = 0;                /* then turn south */
  3216.                     besty = 1;
  3217.             }   }
  3218.             if (bestgood <= -60 && (!(rand() % 5)))
  3219.                 wormqueue(player, 0, 0);
  3220.             elif (bestgood < 0 && (!(rand() % 2)))
  3221.                 wormqueue(player, 0, 0);
  3222.             elif (bestx != worm[player].deltax || besty != worm[player].deltay)
  3223.                 wormqueue(player, bestx, besty);
  3224.     }   }
  3225.  
  3226.     /* remove a keystroke from the worm queue */
  3227.  
  3228.     if (worm[player].pos != -1)
  3229.     {   if (thewormqueue[player][0].deltax == 0 && thewormqueue[player][0].deltay == 0)
  3230.             wormbullet(player);
  3231.         else turnworm(player, thewormqueue[player][0].deltax, thewormqueue[player][0].deltay);
  3232.         if (--worm[player].pos != -1)
  3233.         {   for (i = 0; i <= worm[player].pos; i++)
  3234.             {   thewormqueue[player][i].deltax = thewormqueue[player][i + 1].deltax;
  3235.                 thewormqueue[player][i].deltay = thewormqueue[player][i + 1].deltay;
  3236.     }   }   }
  3237.  
  3238.     /* move worm */
  3239.  
  3240.     change(worm[player].x, worm[player].y, worm[player].last);
  3241.     worm[player].x = xwrap(worm[player].x + worm[player].deltax);
  3242.     worm[player].y = ywrap(worm[player].y + worm[player].deltay);
  3243.     if (worm[player].freedom)
  3244.         worm[player].last = FIRSTFIRE + player;
  3245.     else worm[player].last = FIRSTTAIL + player;
  3246.  
  3247.     for (i = 0; i <= CREATURES; i++)
  3248.     {   if (creature[i].alive && creature[i].species == DOG && creature[i].dormant > DORMANT && creature[i].type == player)
  3249.         {   if (!worm[player].rammed)
  3250.                 dogqueue(i, worm[player].deltax, worm[player].deltay);
  3251.             if (creature[i].dormant < CHASING)
  3252.             {   creature[i].dormant++;
  3253.                 draw(creature[i].x, creature[i].y, DOGAWAKENING);
  3254.     }   }   }
  3255.  
  3256.     /* The deltas are not changed back to the range of -1..1 until after
  3257.     the dogs have looked at the queue. This enables them to jump properly. */
  3258.  
  3259.     worm[player].rammed = FALSE;
  3260.     worm[player].deltax = bsign(worm[player].deltax);
  3261.     worm[player].deltay = bsign(worm[player].deltay);
  3262.  
  3263.     /*  check for enclosure
  3264.         #####
  3265.         #...#
  3266.         #...# . = interior
  3267.         #...# # = tail
  3268.         ####! ! = head */
  3269.  
  3270.     for (interior = 2; interior <= 7; interior++) // for each size of interior
  3271.     {   for (i = 0; i <= 3; i++) // four times, once for each direction
  3272.         {   x = worm[player].x;
  3273.             y = worm[player].y;
  3274.             ok = TRUE;
  3275.  
  3276.             for (k = 0; k <= interior; k++)
  3277.             {   x += deltas[i].deltax[0];
  3278.                 y += deltas[i].deltay[0];
  3279.                 if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  3280.                 {   ok = FALSE;
  3281.                     break;
  3282.             }   }
  3283.             for (k = 0; k <= interior; k++)
  3284.             {   x += deltas[i].deltax[1];
  3285.                 y += deltas[i].deltay[1];
  3286.                 if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  3287.                 {   ok = FALSE;
  3288.                     break;
  3289.             }   }
  3290.             for (k = 0; k <= interior; k++)
  3291.             {   x += deltas[i].deltax[2];
  3292.                 y += deltas[i].deltay[2];
  3293.                 if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  3294.                 {   ok = FALSE;
  3295.                     break;
  3296.             }   }
  3297.             // now the last side
  3298.             for (k = 0; k <= interior - 1; k++)
  3299.             {   x += deltas[i].deltax[3];
  3300.                 y += deltas[i].deltay[3];
  3301.                 if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  3302.                 {   ok = FALSE;
  3303.                     break;
  3304.             }   }
  3305.             if (ok)
  3306.             {   effect(FXDO_ENCLOSE);
  3307.                 enclosed = TRUE;
  3308.                 if (enclose[i].leftx < -1)
  3309.                     enclose[i].leftx = -interior;
  3310.                 elif (enclose[i].leftx > 1)
  3311.                     enclose[i].leftx = interior + 1;
  3312.                 if (enclose[i].rightx < -1)
  3313.                     enclose[i].rightx = -(interior + 1);
  3314.                 elif (enclose[i].rightx > 1)
  3315.                     enclose[i].rightx = interior;
  3316.                 if (enclose[i].topy < -1)
  3317.                     enclose[i].topy = -interior;
  3318.                 elif (enclose[i].topy > 1)
  3319.                     enclose[i].topy = interior + 1;
  3320.                 if (enclose[i].bottomy < -1)
  3321.                     enclose[i].bottomy = -(interior + 1);
  3322.                 elif (enclose[i].bottomy > 1)
  3323.                     enclose[i].bottomy = interior;
  3324.  
  3325.                   leftx = worm[player].x + enclose[i].leftx;
  3326.                  rightx = worm[player].x + enclose[i].rightx;
  3327.                    topy = worm[player].y + enclose[i].topy;
  3328.                 bottomy = worm[player].y + enclose[i].bottomy;
  3329.                 // assert(leftx >= 0 && rightx <= FIELDX && topy >= 0 && bottomy <= FIELDY && leftx < rightx && topy < bottomy);
  3330.  
  3331.                 for (x = leftx; x <= rightx; x++)
  3332.                 {   for (y = topy; y <= bottomy; y++)
  3333.                     {   d = field[x][y];
  3334.                         if ((d >= FIRSTEMPTY && d <= LASTEMPTY) || (d >= FIRSTTAIL && d <= LASTTAIL))
  3335.                         {   if (worm[player].bias)
  3336.                             {   change(x, y, GOLD);
  3337.                                 wormscore(player, ENCLOSUREPOINT + TURNTOGOLD);
  3338.                             } elif (player != d - FIRSTTAIL)
  3339.                             {   change(x, y, FIRSTTAIL + player);
  3340.                                 wormscore(player, ENCLOSUREPOINT);
  3341.     }   }   }   }   }   }   }
  3342.  
  3343.     // move protectors
  3344.  
  3345.     for (i = 0; i <= PROTECTORS; i++)
  3346.     {   if (protector[player][i].alive)
  3347.         {   if (protector[player][i].visible)
  3348.             {   change(protector[player][i].x, protector[player][i].y, protector[player][i].last);
  3349.             } else protector[player][i].visible = TRUE;
  3350.             protector[player][i].last = EMPTY;
  3351.             if (i == NOSE)
  3352.             {   protector[player][i].relx = worm[player].deltax * NOSEDISTANCE;
  3353.                 protector[player][i].rely = worm[player].deltay * NOSEDISTANCE;
  3354.                 if (!worm[player].affixer)
  3355.                 {   if (worm[player].position == -1)
  3356.                         worm[player].posidir = 1;
  3357.                     elif (worm[player].position == 1)
  3358.                         worm[player].posidir = -1;
  3359.                     worm[player].position += worm[player].posidir;
  3360.                     if (worm[player].deltax == 0)
  3361.                         protector[player][i].relx = worm[player].position;
  3362.                     elif (worm[player].deltay == 0)
  3363.                         protector[player][i].rely = worm[player].position;
  3364.                     elif (worm[player].position == -1)
  3365.                         protector[player][i].relx = worm[player].deltax * (NOSEDISTANCE - 1);
  3366.                     elif (worm[player].position == 1)
  3367.                         protector[player][i].rely = worm[player].deltay * (NOSEDISTANCE - 1);
  3368.             }   }
  3369.             elif (!worm[player].affixer)
  3370.             {   if (protector[player][i].relx == 1 && protector[player][i].rely == -1)
  3371.                 {   protector[player][i].deltax = 0;
  3372.                     protector[player][i].deltay = 1;
  3373.                 } elif (protector[player][i].relx == 1 && protector[player][i].rely == 1)
  3374.                 {   protector[player][i].deltax = -1;
  3375.                     protector[player][i].deltay = 0;
  3376.                 } elif (protector[player][i].relx == -1 && protector[player][i].rely == 1)
  3377.                 {   protector[player][i].deltax = 0;
  3378.                     protector[player][i].deltay = -1;
  3379.                 } elif (protector[player][i].relx == -1 && protector[player][i].rely == -1)
  3380.                 {   protector[player][i].deltax = 1;
  3381.                     protector[player][i].deltay = 0;
  3382.                 }
  3383.                 protector[player][i].relx += protector[player][i].deltax;
  3384.                 protector[player][i].rely += protector[player][i].deltay;
  3385.             }
  3386.             protector[player][i].x = worm[player].x + protector[player][i].relx;
  3387.             protector[player][i].y = worm[player].y + protector[player][i].rely;
  3388.             if (!valid(protector[player][i].x, protector[player][i].y))
  3389.             {   protector[player][i].visible = FALSE;
  3390.     }   }   }
  3391.  
  3392.     // head collision detection
  3393.     wormcol(player, worm[player].x, worm[player].y, enclosed);
  3394.     // draw head
  3395.     field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
  3396.     drawhead(player, worm[player].x, worm[player].y);
  3397.  
  3398.     updatearrow(worm[player].arrowy);
  3399.     worm[player].arrowy = worm[player].y;
  3400.     updatearrow(worm[player].arrowy);
  3401.  
  3402.     // protector collision detection
  3403.     for (thisprot = 0; thisprot <= PROTECTORS; thisprot++)
  3404.     {   if (protector[player][thisprot].alive && protector[player][thisprot].visible)
  3405.         {   protcol(player, protector[player][thisprot].x, protector[player][thisprot].y, thisprot);
  3406.             // draw protector
  3407.             if (protector[player][thisprot].alive && protector[player][thisprot].visible) // in case protector has just been killed, etc.
  3408.             {   change(protector[player][thisprot].x, protector[player][thisprot].y, FIRSTPROTECTOR + player);
  3409.     }   }   }
  3410.  
  3411.     if (worm[player].cutter)
  3412.     {   // straight ahead
  3413.         x = xwrap(worm[player].x + worm[player].deltax);
  3414.         y = ywrap(worm[player].y + worm[player].deltay);
  3415.         score += squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3416.         // left
  3417.         if (!worm[player].deltax || !worm[player].deltay)
  3418.         {   // if orthagonal
  3419.             x = xwrap(worm[player].x + worm[player].deltay);
  3420.             y = ywrap(worm[player].y - worm[player].deltax);
  3421.         } else // diagonal
  3422.         {   if (worm[player].deltax == worm[player].deltay)
  3423.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3424.                 y = ywrap(worm[player].y - worm[player].deltay);
  3425.             } else
  3426.             {   x = xwrap(worm[player].x - worm[player].deltax);
  3427.                 y = ywrap(worm[player].y + worm[player].deltay);
  3428.         }   }
  3429.         score += squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3430.         // right
  3431.         if (!worm[player].deltax || !worm[player].deltay)
  3432.         {   // if orthagonal
  3433.             x = xwrap(worm[player].x - worm[player].deltay);
  3434.             y = ywrap(worm[player].y + worm[player].deltax);
  3435.         } else // diagonal
  3436.         {   if (worm[player].deltax == worm[player].deltay)
  3437.             {   x = xwrap(worm[player].x - worm[player].deltax);
  3438.                 y = ywrap(worm[player].y + worm[player].deltay);
  3439.             } else
  3440.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3441.                 y = ywrap(worm[player].y - worm[player].deltay);
  3442.         }   }
  3443.         score += squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3444.         // ahead left
  3445.         if (!worm[player].deltax || !worm[player].deltay)
  3446.         {   // if orthagonal
  3447.             if (worm[player].deltax) // if east or west
  3448.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3449.                 y = ywrap(worm[player].y - worm[player].deltax);
  3450.             } else // north or south
  3451.             {   x = xwrap(worm[player].x + worm[player].deltay);
  3452.                 y = ywrap(worm[player].y + worm[player].deltay);
  3453.         }   }
  3454.         else // diagonal
  3455.         {   if (worm[player].deltax == worm[player].deltay)
  3456.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3457.                 y = worm[player].y;
  3458.             } else
  3459.             {   x = worm[player].x;
  3460.                 y = ywrap(worm[player].y + worm[player].deltay);
  3461.         }   }
  3462.         score += squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3463.         // ahead right
  3464.         if (!worm[player].deltax || !worm[player].deltay)
  3465.         {   // if orthagonal
  3466.             if (worm[player].deltax) // if east or west
  3467.             {   x = xwrap(worm[player].x + worm[player].deltax);;
  3468.                 y = ywrap(worm[player].y + worm[player].deltax);
  3469.             } else // north or south
  3470.             {   x = xwrap(worm[player].x - worm[player].deltay);
  3471.                 y = ywrap(worm[player].y + worm[player].deltay);
  3472.         }   }
  3473.         else // diagonal
  3474.         {   if (worm[player].deltax == worm[player].deltay)
  3475.             {   x = worm[player].x;
  3476.                 y = ywrap(worm[player].y + worm[player].deltay);
  3477.             } else
  3478.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3479.                 y = worm[player].y;
  3480.         }   }
  3481.         score += squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3482.         wormscore(player, score);
  3483. }   }
  3484.  
  3485. MODULE void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot)
  3486. {   UBYTE c = field[x][y];
  3487.     SBYTE i;
  3488.     ULONG score = 0;
  3489.  
  3490.     if (c >= FIRSTHEAD && c <= LASTHEAD)
  3491.         protworm(x, y, player, c - FIRSTHEAD);
  3492.     elif (c >= FIRSTTAIL && c <= LASTTAIL)
  3493.     {   if (player == c - FIRSTTAIL || worm[player].mode == TONGUE)
  3494.             protector[player][thisprot].visible = FALSE;
  3495.     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  3496.         protprot(x, y, player, c - FIRSTPROTECTOR);
  3497.     elif (c == STONE || c == WOOD || c == METAL || c == TIMEBOMB || c == TELEPORT)
  3498.         protector[player][thisprot].visible = FALSE;
  3499.     elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  3500.     {   i = whichcreature(x, y, MISSILE, 255);
  3501.         protmissile(x, y, player, i);
  3502.     } elif (c == WHIRLWIND)
  3503.     {   i = whichcreature(x, y, WHIRLWIND, 255);
  3504.         protwhirlwind(x, y, player, i);
  3505.     } elif (c == DOG)
  3506.     {   i = whichcreature(x, y, DOG, 255);
  3507.         protdog(x, y, player, i);
  3508.     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  3509.     {   i = whichcreature(x, y, DRIP, 255);
  3510.         protdrip(x, y, player, i);
  3511.     } elif (c == PENGUIN)
  3512.     {   i = whichcreature(x, y, PENGUIN, 255);
  3513.         protpenguin(x, y, player, i);
  3514.     } elif (c == ORB)
  3515.     {   i = whichcreature(x, y, ORB, 255);
  3516.         protorb(x, y, player, i);
  3517.     } elif (c == FRAGMENT)
  3518.     {   i = whichcreature(x, y, FRAGMENT, 255);
  3519.         protfrag(x, y, player, i);
  3520.     } elif (c == CLOUD)
  3521.     {   i = whichcreature(x, y, CLOUD, 255);
  3522.         cloudprot(x, y, i, player);
  3523.     } elif (c == FIRSTFIRE + player)
  3524.     {   protector[player][thisprot].visible = FALSE;
  3525.     } elif (c == OCTOPUS)
  3526.     {   effect(FXUSE_PROTECTOR);
  3527.         creature[whichcreature(x, y, OCTOPUS, 255)].alive = FALSE;
  3528.         protector[player][thisprot].last = BONUS;
  3529.         score += KILLOCTOPUS;
  3530.         if (worm[player].bias)
  3531.         {   worm[player].lives += OCTOPUSBLOOD;
  3532.             stat(player, LIFE);
  3533.     }   }
  3534.     elif (c == GOAT)
  3535.     {   effect(FXUSE_PROTECTOR);
  3536.         effect(FXDEATH_GOAT);
  3537.         creature[whichcreature(x, y, GOAT, 255)].alive = FALSE;
  3538.         protector[player][thisprot].last = BONUS;
  3539.         score += KILLGOAT;
  3540.         if (worm[player].bias)
  3541.         {   worm[player].lives += GOATBLOOD;
  3542.             stat(player, LIFE);
  3543.     }   }
  3544.     else bothcol(player, x, y);
  3545.     wormscore(player, score);
  3546. }
  3547.  
  3548. MODULE void bothcol(SBYTE player, SBYTE x, SBYTE y)
  3549. {   UBYTE c = field[x][y];
  3550.     SBYTE i, j;
  3551.     ULONG score = 0;
  3552.  
  3553.     if (c >= FIRSTLETTER && c <= LASTLETTER)
  3554.     {   wormletter(player, c);
  3555.         putletter(player);
  3556.     } elif (c <= LASTOBJECT)
  3557.     {   score += wormobject(player, x, y);
  3558.     } else
  3559.     {   switch(c)
  3560.         {
  3561.         case EMPTY:
  3562.             score += EMPTYPOINT;
  3563.         break;
  3564.         case SILVER:
  3565.             score += SILVERPOINT;
  3566.         break;
  3567.         case GOLD:
  3568.             score += GOLDPOINT;
  3569.         break;
  3570.         case DYNAMITE:
  3571.             effect(FXUSE_BOMB);
  3572.             banging = TRUE;
  3573.             bangdynamite(x, y, player);
  3574.             score += worm[player].dynamitescore;
  3575.             worm[player].dynamitescore = 0;
  3576.         break;
  3577.         case SKULL:
  3578.             effect(FXGET_SKULL);
  3579.             score += SKULLPOINT;
  3580.             j = -1; // for safety
  3581.             for (i = 0; i <= 3; i++)
  3582.             {   if (!worm[i].lives && x == worm[i].x && y == worm[i].y && worm[i].control != NONE)
  3583.                     j = i;
  3584.             }
  3585.             if (j != -1)
  3586.             {   worm[player].bias += worm[j].bias;
  3587.                 if (worm[player].bias > 0)
  3588.                 {   if (worm[player].armour > BIASLIMIT)
  3589.                         worm[player].armour = BIASLIMIT;
  3590.                     stat(player, BIAS);
  3591.                     worm[j].bias = 0;
  3592.                     stat(j, BIAS);
  3593.                 }
  3594.                 worm[player].multi *= worm[j].multi;
  3595.                 if (worm[player].multi > 1)
  3596.                 {   if (worm[player].multi > MULTILIMIT)
  3597.                         worm[player].multi = MULTILIMIT;
  3598.                 }
  3599.                 worm[player].power += worm[j].power;
  3600.                 if (worm[player].power > 1)
  3601.                 {   if (worm[player].power > POWERLIMIT)
  3602.                         worm[player].power = POWERLIMIT;
  3603.                     stat(player, POWER);
  3604.                     worm[j].power = 0;
  3605.                     stat(j, POWER);
  3606.                 }
  3607.                 worm[player].ammo += worm[j].ammo;
  3608.                 if (worm[player].ammo > 0)
  3609.                 {   if (worm[player].ammo > AMMOLIMIT)
  3610.                         worm[player].ammo = AMMOLIMIT;
  3611.                     stat(player, AMMO);
  3612.                     worm[j].ammo = 0;
  3613.                     stat(j, AMMO);
  3614.                 }
  3615.                 worm[player].armour += worm[j].armour;
  3616.                 if (worm[player].armour > 0)
  3617.                 {   if (worm[player].armour > MODELIMIT)
  3618.                         worm[player].armour = MODELIMIT;
  3619.                     stat(player, ARMOUR);
  3620.                     worm[j].armour = 0;
  3621.                     stat(j, ARMOUR);
  3622.                 }
  3623.                 worm[player].tongue += worm[j].tongue;
  3624.                 if (worm[player].tongue > 0)
  3625.                 {   if (worm[player].armour > MODELIMIT)
  3626.                         worm[player].armour = MODELIMIT;
  3627.                     stat(player, TONGUE);
  3628.                     worm[j].tongue = 0;
  3629.                     stat(j, TONGUE);
  3630.                 }
  3631.                 if (worm[player].armour > 0 || worm[player].tongue > 0)
  3632.                 {   if (worm[player].armour >= worm[player].tongue)
  3633.                         worm[player].mode = ARMOUR;
  3634.                     else worm[player].mode = TONGUE;
  3635.                 }
  3636.                 if (worm[j].nitro)
  3637.                 {   worm[player].nitro = TRUE;
  3638.                     stat(player, NITRO);
  3639.                     worm[j].nitro = FALSE;
  3640.                     worm[j].speed = NORMAL;
  3641.                     stat(j, NITRO);
  3642.                 }
  3643.                 if (worm[j].affixer)
  3644.                 {   worm[player].affixer = TRUE;
  3645.                     icon(player, AFFIXER);
  3646.                     worm[j].affixer = FALSE;
  3647.                     icon(j, AFFIXER);
  3648.                 }
  3649.                 if (worm[j].remnants)
  3650.                 {   worm[player].remnants = TRUE;
  3651.                     icon(player, REMNANTS);
  3652.                     worm[j].remnants = FALSE;
  3653.                     icon(j, REMNANTS);
  3654.                 }
  3655.                 if (worm[j].sideshot)
  3656.                 {   worm[player].sideshot = TRUE;
  3657.                     icon(player, SIDESHOT);
  3658.                     worm[j].sideshot = FALSE;
  3659.                     icon(j, SIDESHOT);
  3660.                 }
  3661.                 if (worm[j].pusher)
  3662.                 {   worm[player].pusher = TRUE;
  3663.                     icon(player, PUSHER);
  3664.                     worm[j].pusher = FALSE;
  3665.                     icon(j, PUSHER);
  3666.                 }
  3667.                 if (worm[j].cutter)
  3668.                 {   worm[player].cutter += worm[j].cutter;
  3669.                     icon(player, CUTTER);
  3670.                     worm[j].cutter = 0;
  3671.                     icon(j, CUTTER);
  3672.                 }
  3673.                 for (i = 0; i <= LETTERS; i++)
  3674.                     if (letters[j][i])
  3675.                     {   drawletter(j, FIRSTLETTER + i, BLACK);
  3676.                         if (!letters[player][i])
  3677.                         {   letters[player][i] = TRUE;
  3678.                             drawletter(player, FIRSTLETTER + i, NORMAL);
  3679.                     }   }
  3680.             } else ; // assert(0);
  3681.         break;
  3682.         default:
  3683.         break;
  3684.     }   } 
  3685.     wormscore(player, score);
  3686. }
  3687.  
  3688. AGLOBAL void wormscore(SBYTE player, LONG score)
  3689. {   worm[player].score += score * worm[player].multi * players;
  3690.     stat(player, BONUS);
  3691. }
  3692.  
  3693. SBYTE xwrap(SBYTE x)
  3694. {    if (x < 0)
  3695.         x += FIELDX + 1;
  3696.     elif (x > FIELDX)
  3697.         x -= FIELDX + 1;
  3698.     return(x);
  3699. }
  3700. SBYTE ywrap(SBYTE y)
  3701. {    if (y < 0)
  3702.         y += FIELDY + 1;
  3703.     elif (y > FIELDY)
  3704.         y -= FIELDY + 1;
  3705.     return(y);
  3706. }
  3707.  
  3708. MODULE void ramming(SBYTE player)
  3709. {   SBYTE i;
  3710.  
  3711.     worm[player].rammed = TRUE;
  3712.     worm[player].x = xwrap(worm[player].x - worm[player].deltax);
  3713.     worm[player].y = ywrap(worm[player].y - worm[player].deltay);
  3714.     for (i = 0; i <= PROTECTORS; i++)
  3715.     {   /* no point checking whether the protectors are alive or dead */
  3716.         protector[player][i].x -= worm[player].deltax;
  3717.         protector[player][i].y -= worm[player].deltay;
  3718. }   }
  3719.  
  3720. MODULE SWORD atleast(SWORD value, SWORD minimum)
  3721. {    if (value < minimum)
  3722.         return(minimum);
  3723.     else return(value);
  3724. }
  3725.  
  3726. MODULE void orbscore(SBYTE which, ULONG score)
  3727. {   creature[which].score += score * creature[which].multi;
  3728. }
  3729.  
  3730. MODULE void __inline change(SBYTE x, SBYTE y, UBYTE image)
  3731. {   // assert(valid(x, y));
  3732.     field[x][y] = image;
  3733.     draw(x, y, image);
  3734. }
  3735.  
  3736. MODULE void createmissile(UBYTE player, SBYTE x, SBYTE y)
  3737. {   UBYTE i;
  3738.  
  3739.     for (i = 0; i <= CREATURES; i++)
  3740.         if (!creature[i].alive)
  3741.         {   effect(FXBORN_MISSILE);
  3742.             creature[i].alive      = TRUE;
  3743.             creature[i].x          = x;
  3744.             creature[i].y          = y;
  3745.             creature[i].species    = MISSILE;
  3746.             creature[i].type       = player;
  3747.             creature[i].last       = EMPTY;
  3748.             creature[i].visible    = FALSE;
  3749.             if (level)
  3750.                 creature[i].speed  = (SBYTE) atleast(MISSILESPEED - (level / 2), 1);
  3751.             else creature[i].speed = BONUSMISSILESPEED;
  3752.             break;
  3753. }       }
  3754.  
  3755. /* WormWars FSET format for fieldset contents and high score table (Amiga
  3756. and IBM-PC), as follows:
  3757.  
  3758. header
  3759.         TEXT[]                          "FSET x.x" (NULL-terminated)
  3760.     SBYTE                levels;
  3761. high score table
  3762.     for (slot = 0; slot <= HISCORES; slot++)
  3763.     {    SBYTE            hiscore[slot].player,
  3764.                     hiscore[slot].level;
  3765.         SLONG            hiscore[slot].score;
  3766.         TEXT[]            hiscore[slot].name (NULL-terminated)
  3767.         TEXT[]            hiscore[slot].time (NULL-terminated)
  3768.         TEXT[]            hiscore[slot].date (NULL-terminated)
  3769.     }
  3770. level data
  3771.     for (level = 0; level <= levels; level++)
  3772.     {    SBYTE            startx[level],
  3773.                                         starty[level];
  3774.         ABOOL            teleport[level][0].alive;
  3775.         SBYTE            teleport[level][0].x,
  3776.                                         teleport[level][0].y;
  3777.         ABOOL            teleport[level][1].alive;
  3778.         SBYTE            teleport[level][1].x,
  3779.                                         teleport[level][1].y;
  3780.         for (x = 0; x <= FIELDX; x++)
  3781.             for (y = 0; y <= FIELDY; y++)
  3782.                 SBYTE    board[level][x][y];
  3783.     }
  3784. version string
  3785.         TEXT[]                          "$VER: Worm Wars x.x (dd.mm.yy) $" (NULL-terminated) */
  3786.  
  3787. MODULE SBYTE onlyworm(ABOOL alive)
  3788. {   SBYTE i,
  3789.           theworm = -1, // to prevent spurious warnings
  3790.           worms   = 0;
  3791.  
  3792.     for (i = 0; i <= 3; i++)
  3793.         if (worm[i].control != NONE && ((!alive) || worm[i].lives))
  3794.         {   theworm = i;
  3795.             worms++;
  3796.         }
  3797.     if (worms == 1)
  3798.         return (SBYTE) theworm;
  3799.     else return -1;
  3800. }
  3801.  
  3802. /* cloud, prot, worm, dog, drip, frag, missile, orb, penguin, whirlwind
  3803.  
  3804. Whichever is earlier in that list comes earlier in the function name. For
  3805. example, frag-orb and orb-frag collisions both use fragorb(): there is no
  3806. such routine as orbfrag(). Also, there are no such routines as dripdrip()
  3807. and penguinpenguin(). */
  3808.  
  3809. MODULE void dogdog(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3810. {   creature[which1].alive = FALSE;
  3811.     creature[which2].alive = FALSE;
  3812.     change(x, y, LIFE);
  3813. }
  3814. MODULE void dogdrip(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3815. {   creature[which1].alive = FALSE;
  3816. }
  3817. MODULE void dogfrag(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3818. {   creature[which1].alive = FALSE;
  3819.     creature[which2].alive = FALSE;
  3820.     change(x, y, BONUS);
  3821. }
  3822. MODULE void dogmissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3823. {   creature[which1].alive = FALSE;
  3824.     creature[which2].alive = FALSE;
  3825.     change(x, y, BONUS);
  3826. }
  3827. MODULE void dogorb(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3828. {   creature[which1].alive = FALSE;
  3829. }
  3830. MODULE void dogpenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3831. {   creature[which2].alive = FALSE;
  3832. }
  3833. MODULE void dogwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3834. {   creature[which1].alive = FALSE;
  3835. }
  3836. MODULE void dripfrag(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3837. {   creature[which1].alive = FALSE;
  3838.     creature[which2].alive = FALSE;
  3839.     change(x, y, BONUS);
  3840. }
  3841. MODULE void dripmissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3842. {   /* drip lives, missile dies */
  3843.     creature[which2].alive = FALSE;
  3844. }
  3845. MODULE void driporb(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3846. {   creature[which1].alive = FALSE;
  3847.     if (creature[which2].mode != ARMOUR)
  3848.     {   creature[which2].explode = TRUE;
  3849.         draw(x, y, EMPTY);
  3850. }   }
  3851. MODULE void drippenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3852. {   creature[which2].alive = FALSE;
  3853. }
  3854. MODULE void dripwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3855. {   creature[which1].alive = FALSE;
  3856. }
  3857. MODULE void fragfrag(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3858. {   effect(FXDEATH_FRAGMENT);
  3859.     creature[which1].alive = FALSE;
  3860.     creature[which2].alive = FALSE;
  3861.     draw(x, y, EMPTY);
  3862. }
  3863. MODULE void fragmissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3864. {   creature[which1].alive = FALSE;
  3865.     creature[which2].alive = FALSE;
  3866.     change(x, y, EMPTY);
  3867. }
  3868. MODULE void fragorb(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3869. {   creature[which1].alive = FALSE;
  3870.     if (creature[which2].mode != ARMOUR)
  3871.     {   creature[which2].explode = TRUE;
  3872.         draw(x, y, EMPTY);
  3873.     } else effect(FXUSE_ARMOUR);
  3874. }
  3875. MODULE void fragpenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3876. {   creature[which2].alive = FALSE;
  3877. }
  3878. MODULE void fragwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3879. {   creature[which1].alive = FALSE;
  3880. }
  3881. MODULE void missilemissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3882. {   creature[which1].alive = FALSE;
  3883.     creature[which2].alive = FALSE;
  3884.     change(x, y, BONUS);
  3885. }
  3886. MODULE void missilepenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3887. {   creature[which2].alive = FALSE;
  3888. }
  3889. MODULE void missilewhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3890. {   creature[which1].alive = FALSE;
  3891. }
  3892. MODULE void orborb(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3893. {   effect(FXDEATH_ORB);
  3894.     creature[which1].alive = FALSE;
  3895.     creature[which2].alive = FALSE;
  3896.     change(x, y, BONUS);
  3897. }
  3898. MODULE void orbmissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3899. {   if (creature[which1].mode != ARMOUR)
  3900.     {   effect(FXDEATH_ORB);
  3901.         creature[which1].alive = FALSE;
  3902.         creature[which2].alive = FALSE;
  3903.         change(x, y, BONUS);
  3904.         wormscore(creature[which2].type, creature[which1].score);
  3905.         if (worm[creature[which2].type].bias)
  3906.         {   worm[creature[which2].type].lives += ORBBLOOD;
  3907.             stat(creature[which2].type, LIFE);
  3908.     }   }
  3909.     else effect(FXUSE_ARMOUR);
  3910. }
  3911. MODULE void orbpenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3912. {   creature[which2].alive = FALSE;
  3913.     if (creature[which1].mode == ARMOUR)
  3914.         orbscore(which1, KILLPENGUIN);
  3915.     else
  3916.     {   creature[which1].alive = FALSE;
  3917.         change(x, y, BONUS);
  3918. }   }
  3919. MODULE void orbwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3920. {   creature[which1].alive = FALSE;
  3921. }
  3922. MODULE void penguinwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3923. {   creature[which1].alive = FALSE;
  3924. }
  3925. MODULE void whirlwindwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3926. {   creature[which1].alive = FALSE;
  3927.     creature[which2].alive = FALSE;
  3928.     change(x, y, LIFE);
  3929. }
  3930. MODULE void wormdog(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3931. {   if (creature[which2].dormant == DORMANT)
  3932.     {   effect(FXBORN_DOG);
  3933.         creature[which2].dormant = AWAKENING;
  3934.         creature[which2].type = which1;
  3935.         worm[which1].last = DOG;
  3936.     } else
  3937.     {   creature[which2].alive = FALSE;
  3938.         if (worm[which1].mode != ARMOUR)
  3939.         {   worm[which1].alive = FALSE;
  3940.             worm[which1].cause = DOG;
  3941.             worm[which1].victor = -1;
  3942. }   }   }
  3943. MODULE void wormdrip(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3944. {   creature[which2].alive = FALSE;
  3945.     if (which1 == creature[which2].type)
  3946.     {   effect(FXGET_DRIP);
  3947.         wormscore(which1, DRIPBONUS);
  3948.         if (worm[which1].bias)
  3949.         {    worm[which1].lives += DRIPBLOOD;
  3950.             stat(which1, LIFE);
  3951.     }    }
  3952.     else
  3953.     {    worm[which1].alive = FALSE;
  3954.         worm[which1].cause = FIRSTDRIP + creature[which2].type;
  3955.         worm[which1].victor = -1;
  3956. }   }
  3957. MODULE void wormfrag(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3958. {   if (worm[which1].mode != ARMOUR)
  3959.     {    worm[which1].cause = FRAGMENT;
  3960.     worm[which1].victor = -1;
  3961.     worm[which1].alive = FALSE;
  3962.         creature[which2].alive = FALSE;
  3963.     } else
  3964.     {   effect(FXUSE_ARMOUR);
  3965.     reflect(which2);
  3966. }   }
  3967. MODULE void wormmissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3968. {   if (creature[which2].type == which1)
  3969.         creature[which2].visible = FALSE;
  3970.     else
  3971.     {   creature[which2].alive = FALSE;
  3972.     if (worm[which1].mode != ARMOUR)
  3973.     {   worm[which1].cause = FIRSTMISSILE + creature[which2].type;
  3974.               worm[which1].victor = creature[which2].type;
  3975.               worm[which1].alive = FALSE;
  3976.         } else effect(FXUSE_ARMOUR);
  3977. }   }
  3978. MODULE void wormorb(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3979. {   if (worm[which1].mode == ARMOUR)
  3980.     {   effect(FXUSE_ARMOUR);
  3981.         effect(FXDEATH_ORB);
  3982.         wormscore(which1, creature[which2].score);
  3983.         creature[which2].alive = FALSE;
  3984.         if (worm[which1].bias)
  3985.         {   worm[which1].lives += ORBBLOOD;
  3986.             stat(which1, LIFE);
  3987.     }   }
  3988.     else
  3989.     {   if (creature[which2].mode == ARMOUR)
  3990.         {   effect(FXUSE_ARMOUR);
  3991.             orbscore(which2, KILLWORM);
  3992.         } else creature[which2].alive = FALSE;
  3993.     worm[which1].cause = ORB;
  3994.     worm[which1].victor = -1;
  3995.     worm[which1].alive = FALSE;
  3996. }   }
  3997. MODULE void wormpenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3998. {   effect(FXDEATH_PENGUIN);
  3999.     creature[which2].alive = FALSE;
  4000.     if (worm[which1].armour)
  4001.     {   wormscore(which1, KILLPENGUIN);
  4002.     if (worm[which1].bias)
  4003.     {   worm[which1].lives += PENGUINBLOOD;
  4004.         stat(which1, LIFE);
  4005.     }   }
  4006.     else
  4007.     {   worm[which1].alive = FALSE;
  4008.         worm[which1].cause = PENGUIN;
  4009.         worm[which1].victor = -1;
  4010. }   }
  4011. MODULE void wormwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4012. {   worm[which1].cause = WHIRLWIND;
  4013.     worm[which1].victor = -1;
  4014.     worm[which1].alive = FALSE;
  4015. }
  4016. MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4017. {   if (worm[which1].mode != TONGUE && worm[which2].mode != TONGUE)
  4018.     {   /* both worms die */
  4019.         worm[which1].cause  = FIRSTHEAD + which2;
  4020.         worm[which1].alive  = FALSE;
  4021.         worm[which1].victor = -1;
  4022.         worm[which2].cause  = FIRSTHEAD + which1;
  4023.         worm[which2].alive  = FALSE;
  4024.         worm[which2].victor = -1;
  4025.     } elif (worm[which1].mode == TONGUE && worm[which2].mode != TONGUE)
  4026.     {   /* 1st worm lives, 2nd worm dies  */
  4027.         worm[which2].cause  = FIRSTHEAD + which1;
  4028.         worm[which2].alive  = FALSE;
  4029.         worm[which2].victor = which1;
  4030.     } elif (worm[which1].mode != TONGUE && worm[which2].mode == TONGUE)
  4031.     {   /* 1st worm dies, 2nd worm lives */
  4032.         worm[which1].cause  = FIRSTHEAD + which2;
  4033.         worm[which1].alive  = FALSE;
  4034.         worm[which1].victor = which2;
  4035. }   }
  4036. MODULE void protdog(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4037. {   creature[which2].alive = FALSE;
  4038. }
  4039. MODULE void protdrip(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4040. {   creature[which2].alive = FALSE;
  4041.     if (which1 == creature[which2].type)
  4042.     {   effect(FXGET_DRIP);
  4043.         wormscore(which1, DRIPBONUS);
  4044.         if (worm[which1].bias)
  4045.         {    worm[which1].lives += DRIPBLOOD;
  4046.             stat(which1, LIFE);
  4047.     }    }
  4048.     else effect(FXUSE_PROTECTOR);
  4049. }
  4050. MODULE void protfrag(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4051. {   effect(FXUSE_PROTECTOR);
  4052.     reflect(which2);
  4053. }
  4054. MODULE void protmissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4055. {   if (which1 != creature[which2].type)
  4056.     {   effect(FXUSE_PROTECTOR);
  4057.         creature[which2].alive = FALSE;
  4058.     } else creature[which2].visible = FALSE;
  4059. }
  4060. MODULE void protorb(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4061. {   effect(FXUSE_PROTECTOR);
  4062.     effect(FXDEATH_ORB);
  4063.     wormscore(which1, creature[which2].score);
  4064.     creature[which2].alive = FALSE;
  4065.     if (worm[which1].bias)
  4066.     {   worm[which1].lives += ORBBLOOD;
  4067.         stat(which1, LIFE);
  4068. }   }
  4069. MODULE void protpenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4070. {   effect(FXUSE_PROTECTOR);
  4071.     effect(FXDEATH_PENGUIN);
  4072.     wormscore(which1, KILLPENGUIN);
  4073.     creature[which2].alive = FALSE;
  4074.     if (worm[which1].bias)
  4075.     {   worm[which1].lives += PENGUINBLOOD;
  4076.         stat(which1, LIFE);
  4077. }   }
  4078. MODULE void protwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4079. {   UBYTE i;
  4080.  
  4081.     for (i = 0; i <= PROTECTORS; i++)
  4082.          if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  4083.               protector[which1][i].alive = FALSE;    
  4084. }
  4085. MODULE void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4086. {   SBYTE i, j = -1; // to prevent spurious warnings
  4087.  
  4088.     for (i = 0; i <= PROTECTORS; i++)
  4089.          if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  4090.          {    j = i;
  4091.               break;
  4092.          }
  4093.  
  4094.     if (which1 != which2)
  4095.     {   if (worm[which2].mode != ARMOUR)
  4096.         {   effect(FXUSE_PROTECTOR);
  4097.             worm[which2].cause  = FIRSTPROTECTOR + which1;
  4098.             worm[which2].victor = which1;
  4099.             worm[which2].alive  = FALSE;
  4100.         } else
  4101.         {   effect(FXUSE_ARMOUR);
  4102.             protector[which1][j].visible = FALSE;
  4103.     }   }
  4104.     else
  4105.     {   /* protector is over worm's own head; caused by ramming */
  4106.         protector[which1][j].visible = FALSE;
  4107. }   }
  4108. MODULE void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4109. {   SBYTE i, p1 = -1, p2 = -1; // to prevent spurious warnings
  4110.  
  4111.     /* Find both protectors */
  4112.  
  4113.     for (i = 0; i <= PROTECTORS; i++)
  4114.     {   if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  4115.             p1 = i;
  4116.         if (protector[which2][i].alive && protector[which2][i].x == x && protector[which2][i].y == y)
  4117.             p2 = i;
  4118.     }
  4119.     protector[which1][p1].alive = FALSE;
  4120.     protector[which2][p2].alive = FALSE;
  4121.     change(x, y, EMPTY);
  4122. }
  4123. MODULE void cloudcloud(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4124. {   creature[which1].alive = FALSE;
  4125.     creature[which2].alive = FALSE;
  4126.     change(x, y, LIGHTNING);
  4127. }
  4128. MODULE void clouddog(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4129. {   creature[which2].alive = FALSE;
  4130. }
  4131. MODULE void clouddrip(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4132. {   creature[which2].alive = FALSE;
  4133. }
  4134. MODULE void cloudfrag(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4135. {   creature[which1].alive = FALSE;
  4136. }
  4137. MODULE void cloudmissile(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4138. {   creature[which2].alive = FALSE;
  4139. }
  4140. MODULE void cloudorb(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4141. {   creature[which1].alive = FALSE;
  4142. }
  4143. MODULE void cloudpenguin(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4144. {   creature[which2].alive = FALSE;
  4145. }
  4146. MODULE void cloudprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4147. {   creature[which1].alive = FALSE;
  4148. }
  4149. MODULE void cloudwhirlwind(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4150. {   creature[which1].alive = FALSE;
  4151. }
  4152. MODULE void cloudworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  4153. {   creature[which1].alive = FALSE;
  4154.     if (worm[which2].mode != ARMOUR)
  4155.     {   worm[which2].alive = FALSE;
  4156.         worm[which2].cause = CLOUD;
  4157.         worm[which2].victor = -1;
  4158. }   }
  4159.  
  4160. MODULE ULONG wormobject(UBYTE player, SBYTE x, SBYTE y)
  4161. {   AUTO    UBYTE c = field[x][y], d;
  4162.     AUTO    ULONG score = object[c].score;
  4163.     AUTO    UBYTE i, j;
  4164.     AUTO    SBYTE xx, xxx, yy, yyy;
  4165.     AUTO    ABOOL done;
  4166.     PERSIST UBYTE otherfield[FIELDX + 1][FIELDY + 1];
  4167.  
  4168.     for (i = 0; i <= MAGNETS; i++)
  4169.         if (magnet[i].alive && x == magnet[i].x && y == magnet[i].y)
  4170.              magnet[i].alive = FALSE;
  4171.  
  4172.     if (!valid(x, y)) // defensive programming
  4173.     {   return 0;
  4174.  
  4175.         /* AUTO TEXT temp1[SAYLIMIT + 1], temp2[8];
  4176.  
  4177.         strcpy(temp1, "BAD OBJECT AT x: ");
  4178.         stci_d(temp2, x);
  4179.         strcat(temp1, temp2);
  4180.         strcat(temp1, ", y: ");
  4181.         stci_d(temp2, y);
  4182.         strcat(temp1, temp2);
  4183.         strcat(temp1, "!");
  4184.         say(temp1, worm[player].colour);
  4185.         draw(FIELDX + 1, 0, c); // indicates which object
  4186.         Delay(250);
  4187.         clearkybd();
  4188.         anykey(FALSE); */
  4189.     }
  4190.  
  4191.     switch(c)
  4192.     {
  4193.     case BONUS:
  4194.         effect(FXGET_OBJECT);
  4195.         i = rand() % (LETTERS + 1);
  4196.         letters[player][i] = TRUE;
  4197.         drawletter(player, FIRSTLETTER + i, NORMAL);
  4198.     break;
  4199.     case AMMO:
  4200.         effect(FXGET_AMMO);
  4201.         worm[player].ammo += (rand() % 5) + 2; /* 2-6 bullets */
  4202.         stat(player, AMMO);
  4203.     break;
  4204.     case ARMOUR:
  4205.         effect(FXGET_OBJECT);
  4206.         worm[player].armour += MODEADD + (rand() % MODERAND);
  4207.         worm[player].mode = ARMOUR;
  4208.         stat(player, ARMOUR);
  4209.     break;
  4210.     case TONGUE:
  4211.         effect(FXGET_OBJECT);
  4212.         worm[player].tongue += MODEADD + (rand() % MODERAND);
  4213.         worm[player].mode = TONGUE;
  4214.         stat(player, TONGUE);
  4215.         worm[player].last = FIRSTTAIL + player;
  4216.         break;
  4217.     case NITRO:
  4218.         effect(FXGET_NITRO);
  4219.         worm[player].nitro = TRUE;
  4220.         stat(player, NITRO);
  4221.     break;
  4222.     case BOMB:
  4223.         if (worm[player].mode == NOMODE)
  4224.             draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4225.         else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4226.             bombblast(HEAD, player, worm[player].x, worm[player].y);
  4227.     break;
  4228.     case POWER:
  4229.         effect(FXGET_POWERUP);
  4230.         if (worm[player].power < POWERLIMIT)
  4231.         {   worm[player].power += 2;
  4232.             stat(player, POWER);
  4233.         }
  4234.     break;
  4235.     case SLAYER:
  4236.         for (i = 0; i <= CREATURES; i++)
  4237.             if (creature[i].alive)
  4238.             {   if (creature[i].species == ORB)
  4239.                 {   effect(FXDEATH_ORB);
  4240.                     score += creature[i].score;
  4241.                     creature[i].explode = TRUE;
  4242.                     if (worm[player].bias)
  4243.                         worm[player].lives += ORBBLOOD;
  4244.                 } elif (creature[i].species == GOAT)
  4245.                 {   effect(FXDEATH_GOAT);
  4246.                     creature[i].alive = FALSE;
  4247.                     score += KILLGOAT;
  4248.                     if (worm[player].bias)
  4249.                         worm[player].lives += GOATBLOOD;
  4250.                     change(creature[i].x, creature[i].y, BONUS);
  4251.                 } elif (creature[i].species == OCTOPUS)
  4252.                 {   creature[i].alive = FALSE;
  4253.                     score += KILLOCTOPUS;
  4254.                     if (worm[player].bias)
  4255.                         worm[player].lives += OCTOPUSBLOOD;
  4256.                     change(creature[i].x, creature[i].y, BONUS);
  4257.                 } elif (creature[i].species == PENGUIN)
  4258.                 {   effect(FXDEATH_PENGUIN);
  4259.                     creature[i].alive = FALSE;
  4260.                     score += KILLPENGUIN;
  4261.                     if (worm[player].bias)
  4262.                         worm[player].lives += PENGUINBLOOD;
  4263.                     change(creature[i].x, creature[i].y, EMPTY);
  4264.                 } elif (creature[i].species == DRIP || creature[i].species == CLOUD || (creature[i].species == MISSILE && creature[i].type != player))
  4265.                 {   creature[i].alive = FALSE;
  4266.                     change(creature[i].x, creature[i].y, EMPTY);
  4267.             }   }
  4268.         for (i = 0; i <= 3; i++)
  4269.             if (player != i && worm[i].mode != ARMOUR)
  4270.             {   worm[i].alive = FALSE;
  4271.                 worm[i].cause = SLAYER;
  4272.                 worm[i].victor = player;
  4273.             }
  4274.         for (x = 0; x <= FIELDX; x++)
  4275.             for (y = 0; y <= FIELDY; y++)
  4276.                 if (field[x][y] == SLIME)
  4277.                     change(x, y, EMPTY);
  4278.         if (worm[player].bias)
  4279.             stat(player, LIFE); // we do it here once for efficiency
  4280.     break;
  4281.     case PROTECTOR:
  4282.         done = FALSE;
  4283.         for (i = 0; i <= PROTECTORS; i++)
  4284.             if (!protector[player][i].alive && !done)
  4285.             {   do
  4286.                 {   protector[player][i].relx = ((rand() % 2) * 2) - 1;
  4287.                     protector[player][i].rely = ((rand() % 2) * 2) - 1;
  4288.                     for (j = 0; j <= PROTECTORS; j++)
  4289.                         if (i == NOSE || !protector[player][j].alive || protector[player][j].x != xwrap(worm[player].x + protector[player][i].relx) || protector[player][j].y != ywrap(worm[player].y + protector[player][i].rely))
  4290.                         {   effect(FXBORN_PROTECTOR);
  4291.                             done = TRUE;
  4292.                             protector[player][i].alive = TRUE;
  4293.                             protector[player][i].visible = FALSE;
  4294.                             protector[player][i].last = EMPTY;
  4295.                             if (i == NOSE)
  4296.                                 worm[player].position = -1;
  4297.                         }
  4298.                 } while (!done);
  4299.             }
  4300.     break;
  4301.     case MISSILE:
  4302.         createmissile(player, worm[player].x, worm[player].y);
  4303.     break;
  4304.     case LIFE:
  4305.         effect(FXGET_OBJECT);
  4306.         worm[player].lives += (rand() % 5) + 2; /* 2-6 lives */
  4307.         stat(player, LIFE);
  4308.     break;
  4309.     case MULTIPLIER:
  4310.         effect(FXGET_OBJECT);
  4311.         if (worm[player].multi < MULTILIMIT)
  4312.             worm[player].multi *= 2;
  4313.     break;
  4314.     case BIAS:
  4315.         effect(FXGET_OBJECT);
  4316.         worm[player].bias += MODEADD + (rand() % MODERAND);
  4317.         stat(player, BIAS);
  4318.     break;
  4319.     case ICE:
  4320.         effect(FXGET_OBJECT);
  4321.         worm[player].ice += ICEADD + (rand() % ICERAND);
  4322.         ice = player;
  4323.         icon(player, ICE);
  4324.     break;
  4325.     case GROWER:
  4326.         effect(FXGET_GROWER);
  4327.  
  4328.         /* grow silver */
  4329.         for (x = 0; x <= FIELDX; x++)
  4330.             for (y = 0; y <= FIELDY; y++)
  4331.                 if (field[x][y] == SILVER)
  4332.                     for (xx = x - 1; xx <= x + 1; xx++)
  4333.                         for (yy = y - 1; yy <= y + 1; yy++)
  4334.                             if (valid(xx, yy))
  4335.                                 if (field[xx][yy] == EMPTY)
  4336.                                     field[xx][yy] = TEMPSILVER;
  4337.         /* grow gold */
  4338.         for (x = 0; x <= FIELDX; x++)
  4339.             for (y = 0; y <= FIELDY; y++)
  4340.                 if (field[x][y] == GOLD)
  4341.                     for (xx = x - 1; xx <= x + 1; xx++)
  4342.                         for (yy = y - 1; yy <= y + 1; yy++)
  4343.                             if (valid(xx, yy))
  4344.                                 if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPSILVER)
  4345.                                     field[xx][yy] = TEMPGOLD;
  4346.         /* update field */
  4347.         for (x = 0; x <= FIELDX; x++)
  4348.             for (y = 0; y <= FIELDY; y++)
  4349.                 switch (field[x][y])
  4350.                 {
  4351.                 case TEMPGOLD:
  4352.                     change(x, y, GOLD);
  4353.                 break;
  4354.                 case TEMPSILVER:
  4355.                     change(x, y, SILVER);
  4356.                 break;
  4357.                 default:
  4358.                 break;
  4359.                 }
  4360.  
  4361.         if (worm[player].bias)
  4362.         {   // grow dynamite
  4363.             for (xx = x - 1; xx <= x + 1; xx++)
  4364.                 for (yy = y - 1; yy <= y + 1; yy++)
  4365.                     if (valid(xx, yy))
  4366.                         if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPSILVER)
  4367.                             field[xx][yy] = TEMPTAIL;
  4368.             // update field
  4369.             for (x = 0; x <= FIELDX; x++)
  4370.             {   for (y = 0; y <= FIELDY; y++)
  4371.                 {   if (field[x][y] == TEMPTAIL)
  4372.                     {   change(x, y, DYNAMITE);
  4373.         }   }   }   }
  4374.     break;
  4375.     case TREASURE:
  4376.         treasurer = player;
  4377.         if (level)
  4378.         {   secondsperlevel = 0;
  4379.             leveltype = rand() % 3;
  4380.             if (leveltype == 0)
  4381.             {   say("Bonus Level: Treasury!", worm[treasurer].colour);
  4382.                 leveltype = TREASURE;
  4383.             } elif (leveltype == 1)
  4384.             {   say("Bonus Level: Drips!", worm[treasurer].colour);
  4385.                 leveltype = DRIP;
  4386.             } else
  4387.             {   // assert(leveltype == 2);
  4388.                 say("Bonus Level: Penguins!", worm[treasurer].colour);
  4389.                 leveltype = PENGUIN;
  4390.         }   }
  4391.         secondsperlevel += TREASUREADD + (rand() % TREASURERAND);
  4392.         if (level && leveltype != TREASURE)
  4393.             secondsperlevel *= 2;
  4394.         if (secondsperlevel > TIMELIMIT)
  4395.             secondsperlevel = TIMELIMIT;
  4396.         if (level)
  4397.         {   stat(player, BONUS);
  4398.             reallevel = level;
  4399.             level = 0;
  4400.             newlevel(player);
  4401.         }
  4402.     break;
  4403.     case AFFIXER:
  4404.         effect(FXGET_OBJECT);
  4405.         worm[player].affixer = TRUE;
  4406.         icon(player, AFFIXER);
  4407.     break;
  4408.     case SWITCHER:
  4409.         effect(FXGET_OBJECT);
  4410.         for (x = 0; x <= FIELDX; x++)
  4411.         {   for (y = 0; y <= FIELDY; y++)
  4412.             {   if (players >= 2 && field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL && field[x][y] != FIRSTTAIL + player)
  4413.                 {   change(x, y, FIRSTTAIL + player);
  4414.                 } elif (worm[player].bias)
  4415.                 {   if (field[x][y] >= FIRSTFIRE && field[x][y] <= LASTFIRE && field[x][y] != FIRSTFIRE + player)
  4416.                         change(x, y, FIRSTFIRE + player);
  4417.                     elif (field[x][y] == SLIME)
  4418.                         change(x, y, DYNAMITE);
  4419.         }   }   }
  4420.     break;
  4421.     case HEALER:
  4422.         effect(FXGET_OBJECT);
  4423.         if (worm[player].lives < 100)
  4424.             worm[player].lives = 100;
  4425.         else worm[player].lives = LIVESLIMIT;
  4426.         stat(player, LIFE);
  4427.     break;
  4428.     case UMBRELLA:
  4429.         level += (rand() % 2) + 1;
  4430.         if (level >= levels)
  4431.             level = levels; // fixed?
  4432.         for (i = 0; i <= LETTERS; i++)
  4433.             letters[player][i] = TRUE;
  4434.     break;
  4435.     case CLOCK:
  4436.         effect(FXGET_OBJECT);
  4437.         if (secondsleft)
  4438.         {   secondsperlevel += (rand() % CLOCKRAND) + CLOCKADD;
  4439.             if (secondsperlevel > TIMELIMIT)
  4440.                 secondsperlevel = TIMELIMIT;
  4441.         }
  4442.     break;
  4443.     case SLOWER:
  4444.         effect(FXGET_OBJECT);
  4445.         for (i = 0; i <= CREATURES; i++)
  4446.             if (creature[i].alive && creature[i].species != MISSILE)
  4447.                 creature[i].speed = (SBYTE) atleast(creature[i].speed * 2, VERYFAST);
  4448.     break;
  4449.     case PULSE:
  4450.         explosion(xwrap(worm[player].x - worm[player].deltax),
  4451.                   ywrap(worm[player].y - worm[player].deltay),
  4452.                                          worm[player].deltax,
  4453.                                          worm[player].deltay,
  4454.                  PULSE);
  4455.     break;
  4456.     case REMNANTS:
  4457.         effect(FXGET_OBJECT);
  4458.         worm[player].remnants = TRUE;
  4459.         icon(player, REMNANTS);
  4460.     break;
  4461.     case SIDESHOT:
  4462.         effect(FXGET_POWERUP);
  4463.         worm[player].sideshot = TRUE;
  4464.         icon(player, SIDESHOT);
  4465.     break;
  4466.     case MAGNET:
  4467.         effect(FXGET_OBJECT);
  4468.         i = 0;
  4469.         field[x][y] = EMPTY; // so that the magnet itself is destroyed
  4470.         for (xx = 0; xx <= FIELDX; xx++)
  4471.             for (yy = 0; yy <= FIELDY; yy++)
  4472.                 if (field[xx][yy] <= LASTOBJECT)
  4473.                 {   while (magnet[i].alive && i < MAGNETS)
  4474.                        i++;
  4475.                     if (i > MAGNETS)
  4476.                     {   break;
  4477.                     } else
  4478.                     {   magnet[i].x      = xx;
  4479.                         magnet[i].y      = yy;
  4480.                         magnet[i].object = field[xx][yy];
  4481.                         magnet[i].player = player;
  4482.                         magnet[i].alive  = TRUE;
  4483.                         i++;
  4484.                 }   }
  4485.     break;
  4486.     case CUTTER:
  4487.         effect(FXGET_OBJECT);
  4488.         worm[player].cutter += (rand() % CUTTERRAND) + CUTTERADD;
  4489.          icon(player, CUTTER);
  4490.     break;
  4491.     case CYCLONE:
  4492.         /* create cyclones */
  4493.         for (i = 0; i <= CREATURES; i++)
  4494.             if (!(creature[i].alive))
  4495.             {   effect(FXGET_CYCLONE);
  4496.                 done = FALSE;
  4497.                 while (!done)
  4498.                 {   creature[i].x = rand() % (FIELDX + 1);
  4499.                     creature[i].y = (rand() % (FIELDY - 2)) + 3;
  4500.                     d = field[creature[i].x][creature[i].y];
  4501.                     if ((d >= FIRSTEMPTY && d <= LASTEMPTY) || (d >= FIRSTTAIL && d <= LASTTAIL))
  4502.                         done = TRUE;
  4503.                     /* Theoretically, this loop could hang... */
  4504.                 }
  4505.                 creature[i].last = EMPTY;
  4506.                 creature[i].speed = VERYFAST;
  4507.                 creature[i].visible = TRUE;
  4508.                 creature[i].deltax = 0;
  4509.                 creature[i].deltay = 0;
  4510.                 creature[i].species = WHIRLWIND;
  4511.                 creature[i].alive = TRUE;
  4512.                 change(creature[i].x, creature[i].y, WHIRLWIND);
  4513.                 break;
  4514.             }
  4515.     break;
  4516.     case LIGHTNING:
  4517.         effect(FXGET_OBJECT);
  4518.         for (xx = 0; xx <= FIELDX; xx++)
  4519.             for (yy = 0; yy <= FIELDY; yy++)
  4520.                 otherfield[xx][yy] = EMPTY;
  4521.         for (xx = 0; xx <= FIELDX; xx++)
  4522.             for (yy = 0; yy <= FIELDY; yy++)
  4523.                 if (field[xx][yy] == FIRSTTAIL + player)
  4524.                     for (xxx = xx - 1; xxx <= xx + 1; xxx++)
  4525.                         for (yyy = yy - 1; yyy <= yy + 1; yyy++)
  4526.                             if (valid(xxx, yyy))
  4527.                             {   d = field[xxx][yyy];
  4528.                                 if (d == ORB
  4529.                                  || d == GOAT
  4530.                                  || d == MISSILE
  4531.                                  || d == PENGUIN
  4532.                                  || d == FRAGMENT
  4533.                                  || (d >= FIRSTTAIL && d <= LASTTAIL && d != FIRSTTAIL + player)
  4534.                                  || (d >= FIRSTHEAD && d <= LASTHEAD)
  4535.                                  || (d >= FIRSTDRIP && d <= LASTDRIP)
  4536.                                  || d <= LASTOBJECT)
  4537.                                 {   otherfield[xxx][yyy] = TEMPLIGHTNING;
  4538.                                     draw(xxx, yyy, LIGHTNING);
  4539.                             }   }
  4540.         for (xx = 0; xx <= FIELDX; xx++)
  4541.         {   for (yy = 0; yy <= FIELDY; yy++)
  4542.             {   if (otherfield[xx][yy] == TEMPLIGHTNING)
  4543.                 {   d = field[xx][yy];
  4544.                     switch(d)
  4545.                     {
  4546.                     case ORB:
  4547.                         i = whichcreature(xx, yy, ORB, 255);
  4548.                         if (creature[i].mode == ARMOUR)
  4549.                             draw(xx, yy, ORBARMOUR);
  4550.                         else
  4551.                         {   creature[i].alive = FALSE;
  4552.                             score += creature[i].score;
  4553.                             change(xx, yy, BONUS);
  4554.                         }
  4555.                     break;
  4556.                     case GOAT:
  4557.                         creature[whichcreature(xx, yy, GOAT, 255)].alive = FALSE;
  4558.                         score += KILLGOAT;
  4559.                         change(xx, yy, BONUS);
  4560.                     break;
  4561.                     case MISSILE:
  4562.                         i = whichcreature(xx, yy, MISSILE, 255);
  4563.                         if (player != creature[i].type)
  4564.                         {   creature[i].alive = FALSE;
  4565.                             change(xx, yy, EMPTY);
  4566.                         } else draw(xx, yy, FIRSTMISSILE + player);
  4567.                     break;
  4568.                     case PENGUIN:
  4569.                         score += KILLPENGUIN;
  4570.                     // note no break here
  4571.                     case FRAGMENT:
  4572.                         creature[whichcreature(xx, yy, d, 255)].alive = FALSE;
  4573.                         change(xx, yy, EMPTY);
  4574.                     break;
  4575.                     default:
  4576.                         if (d >= FIRSTDRIP && d <= LASTDRIP)
  4577.                         {   creature[whichcreature(xx, yy, DRIP, 255)].alive = FALSE;
  4578.                             score += DRIPBONUS;
  4579.                             if (player == d - FIRSTDRIP && worm[player].bias)
  4580.                             {    worm[player].lives += DRIPBLOOD;
  4581.                                 stat(player, LIFE);
  4582.                         }    }
  4583.                         elif (d >= FIRSTHEAD && d <= LASTHEAD)
  4584.                         {   if (player != d - FIRSTHEAD && worm[d - FIRSTHEAD].mode != ARMOUR)
  4585.                             {   worm[d - FIRSTHEAD].alive = FALSE;
  4586.                                 worm[d - FIRSTHEAD].cause = LIGHTNING;
  4587.                                 worm[d - FIRSTHEAD].victor = player;
  4588.                                 change(xx, yy, EMPTY);
  4589.                         }   }
  4590.                         else /* eg. tail */
  4591.                             change(xx, yy, EMPTY);
  4592.                     break;
  4593.         }   }   }   }
  4594.     break;
  4595.     case PUSHER:
  4596.         effect(FXGET_OBJECT);
  4597.         worm[player].pusher = TRUE;
  4598.         icon(player, PUSHER);
  4599.     break;
  4600.     case FREEDOM:
  4601.         effect(FXGET_OBJECT);
  4602.         worm[player].freedom += FREEDOMADD + (rand() % FREEDOMRAND);
  4603.         if (worm[player].freedom > FREEDOMLIMIT)
  4604.             worm[player].freedom = FREEDOMLIMIT;
  4605.         icon(player, FREEDOM);
  4606.     break;
  4607.     case CONVERTER:
  4608.         effect(FXGET_OBJECT);
  4609.         for (i = 0; i <= CREATURES; i++)
  4610.             if (creature[i].alive && creature[i].species == FRAGMENT)
  4611.             {   xx = creature[i].x;
  4612.                 yy = creature[i].y;
  4613.                 creature[i].alive = FALSE;
  4614.                 change(xx, yy, EMPTY);
  4615.                 createmissile(player, xx, yy);
  4616.             }
  4617.     break;
  4618.     default:
  4619.         // assert(0);
  4620.     break;
  4621.     }
  4622.     return(score);
  4623. }
  4624.  
  4625. void icon(SBYTE player, UBYTE image)
  4626. {   /* Updates one of the boolean icons. The routine checks
  4627.     the status directly. */
  4628.  
  4629.     AUTO    SBYTE x, y;
  4630.  
  4631.     if (!worm[player].statx)
  4632.         x = -7;
  4633.     else x = FIELDX + 2;
  4634.     if (!worm[player].staty)
  4635.         y = (FIELDY / 2) - 3;
  4636.     else y = (FIELDY / 2) + 3;
  4637.  
  4638.     switch(image)
  4639.     {
  4640.     case AFFIXER:
  4641.         if (worm[player].affixer)
  4642.             draw(x, y, AFFIXER);
  4643.         else draw(x, y, BLACKENED);
  4644.     break;
  4645.     case PUSHER:
  4646.         if (worm[player].pusher)
  4647.             draw(x + 1, y, PUSHER);
  4648.         else draw(x + 1, y, BLACKENED);
  4649.     break;
  4650.     case REMNANTS:
  4651.         if (worm[player].remnants)
  4652.             draw(x + 2, y, REMNANTS);
  4653.         else draw(x + 2, y, BLACKENED);
  4654.     break;
  4655.     case SIDESHOT:
  4656.         if (worm[player].sideshot)
  4657.             draw(x + 3, y, SIDESHOT);
  4658.         else draw(x + 3, y, BLACKENED);
  4659.     break;
  4660.     case ICE:
  4661.         if (worm[player].ice)
  4662.             if (worm[player].ice < 3)
  4663.             {    if ((r % 4) <= 1)
  4664.                     draw(x + 4, y, ICE);
  4665.                 else draw(x + 4, y, BLACKENED);
  4666.             }
  4667.             else draw(x + 4, y, ICE);
  4668.         else draw(x + 4, y, BLACKENED);
  4669.     break;
  4670.     case CUTTER:
  4671.         if (worm[player].cutter)
  4672.             if (worm[player].cutter < 10)
  4673.             {    if ((r % 4) <= 1)
  4674.                     draw(x + 5, y, CUTTER);
  4675.                 else draw(x + 5, y, BLACKENED);
  4676.             }
  4677.             else draw(x + 5, y, CUTTER);
  4678.         else draw(x + 5, y, BLACKENED);
  4679.     break;
  4680.     case FREEDOM:
  4681.         if (worm[player].freedom)
  4682.             if (worm[player].freedom < 10)
  4683.             {    if ((r % 4) <= 1)
  4684.                     draw(x + 6, y, FREEDOM);
  4685.                 else draw(x + 6, y, BLACKENED);
  4686.             }
  4687.             else draw(x + 6, y, FREEDOM);
  4688.         else draw(x + 6, y, BLACKENED);
  4689.     break;
  4690.     default:
  4691.     break;
  4692. }   }
  4693.  
  4694. MODULE void wormcol(SBYTE player, SBYTE x, SBYTE y, ABOOL enclosed)
  4695. {   ABOOL flag;
  4696.     UBYTE c = field[x][y], d;
  4697.     SBYTE i, xx, yy;
  4698.     ULONG score = 0;
  4699.  
  4700.     if (c >= FIRSTHEAD && c <= LASTHEAD)
  4701.         wormworm(x, y, player, c - FIRSTHEAD);
  4702.     elif (c == TIMEBOMB)
  4703.     {   /* push timebomb */
  4704.         i = whichcreature(x, y, TIMEBOMB, 255);
  4705.         if (valid(x + worm[player].deltax, y + worm[player].deltay))
  4706.         {   d = field[x + worm[player].deltax][y + worm[player].deltay];
  4707.             if (d <= LASTEMPTY)
  4708.             {   creature[i].x += worm[player].deltax;
  4709.                 creature[i].y += worm[player].deltay;
  4710.                 field[creature[i].x][creature[i].y] = TIMEBOMB;
  4711.                 draw(creature[i].x, creature[i].y, ZERO + creature[i].time);
  4712.             } else
  4713.             {   if (worm[player].mode == NOMODE)
  4714.                     draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4715.                 else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4716.                 bombblast(HEAD, player, worm[player].x, worm[player].y);
  4717.                 creature[i].alive = FALSE;
  4718.         }   }
  4719.         else score += BOMBOVEREDGE;
  4720.     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  4721.         protworm(x, y, c - FIRSTPROTECTOR, player);
  4722.     elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  4723.     {   i = whichcreature(x, y, MISSILE, 255);
  4724.         wormmissile(x, y, player, i);
  4725.     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  4726.     {   i = whichcreature(x, y, DRIP, 255);
  4727.         wormdrip(x, y, player, i);
  4728.     } elif (c == STONE || c == GOAT || c == OCTOPUS || c == METAL || (c >= FIRSTTAIL && c <= LASTTAIL))
  4729.     {   flag = TRUE;
  4730.         if (worm[player].pusher)
  4731.         {   xx = x + worm[player].deltax;
  4732.             yy = y + worm[player].deltay;
  4733.             if (valid(xx, yy))
  4734.             {   d = field[xx][yy];
  4735.                 if (d <= LASTEMPTY)
  4736.                 {   flag = FALSE;
  4737.                     if (c == GOAT || c == OCTOPUS)
  4738.                     {   i = whichcreature(x, y, c, 255);
  4739.                         creature[i].x = xx;
  4740.                         creature[i].y = yy;
  4741.                         creature[i].visible = FALSE;
  4742.                     }
  4743.                     field[xx][yy] = c;
  4744.                     draw(xx, yy, c);
  4745.             }   }                 
  4746.             else
  4747.             {   flag = FALSE;
  4748.                 score += BOMBOVEREDGE;
  4749.         }   }
  4750.         if (flag)
  4751.         {   if (c >= FIRSTTAIL && c <= LASTTAIL)
  4752.             {   if (worm[player].mode == TONGUE)
  4753.                 {   effect(FXUSE_TONGUE);
  4754.                     if (players > 1)
  4755.                         if (player == c - FIRSTTAIL)
  4756.                         {   score += TURNTOSILVER;
  4757.                             worm[player].last = SILVER;
  4758.                         } else
  4759.                         {   score += TURNTOGOLD;
  4760.                             worm[player].last = GOLD;
  4761.                 }       }
  4762.                 elif (!enclosed)
  4763.                 {   worm[player].cause = c;
  4764.                     worm[player].alive = FALSE;
  4765.                     worm[player].victor = c - FIRSTTAIL;
  4766.             }   }
  4767.             else
  4768.             {   worm[player].cause = c;
  4769.                 worm[player].victor = -1;
  4770.                 worm[player].alive = FALSE;
  4771.                 ramming(player);
  4772.     }   }   }
  4773.     elif (c == WOOD)
  4774.     {   if (worm[player].mode != ARMOUR)
  4775.         {   worm[player].cause = WOOD;
  4776.             worm[player].alive = FALSE;
  4777.             worm[player].victor = -1;
  4778.     }   }
  4779.     elif (c == SLIME)
  4780.     {   if (worm[player].mode != ARMOUR)
  4781.         {   worm[player].cause = SLIME;
  4782.             worm[player].alive = FALSE;
  4783.             worm[player].victor = -1;
  4784.     }   }
  4785.     elif (c == PENGUIN)
  4786.     {   i = whichcreature(x, y, PENGUIN, 255);
  4787.         wormpenguin(x, y, player, i);
  4788.     } elif (c == WHIRLWIND)
  4789.     {   i = whichcreature(x, y, WHIRLWIND, 255);
  4790.         wormwhirlwind(x, y, player, i);
  4791.     } elif (c == DOG)
  4792.     {   i = whichcreature(x, y, DOG, 255);
  4793.         wormdog(x, y, player, i);
  4794.     } elif (c == ORB)
  4795.     {   i = whichcreature(x, y, ORB, 255);
  4796.         wormorb(x, y, player, i);
  4797.     } elif (c == FRAGMENT)
  4798.     {   i = whichcreature(x, y, FRAGMENT, 255);
  4799.         wormfrag(x, y, player, i);
  4800.     } elif (c == CLOUD)
  4801.     {   i = whichcreature(x, y, CLOUD, 255);
  4802.         cloudworm(x, y, i, player);
  4803.     } elif (c == TELEPORT)
  4804.     {   i = whichteleport(x, y);
  4805.         if (blocked(i, worm[player].deltax, worm[player].deltay))
  4806.         {   worm[player].cause = TELEPORT;
  4807.             worm[player].victor = -1;
  4808.             worm[player].alive = FALSE;
  4809.             ramming(player);
  4810.         } else
  4811.         {   effect(FXUSE_TELEPORT);
  4812.             score += TELPOINT;
  4813.             worm[player].x = xwrap(teleport[level][partner(i)].x + worm[player].deltax);
  4814.             worm[player].y = ywrap(teleport[level][partner(i)].y + worm[player].deltay);
  4815.     }   }
  4816.     elif (c >= FIRSTFIRE && c <= LASTFIRE)
  4817.     {   if (player != c - FIRSTFIRE && worm[player].mode != ARMOUR)
  4818.         {   worm[player].cause = REMNANTS;
  4819.             worm[player].victor = c - FIRSTFIRE;
  4820.             worm[player].alive = FALSE;
  4821.     }   }
  4822.     else bothcol(player, x, y);
  4823.     wormscore(player, score);
  4824. }
  4825.  
  4826. AGLOBAL void drawhead(SBYTE player, SBYTE x, SBYTE y)
  4827. {   if (worm[player].alive)
  4828.     {   if (worm[player].mode == NOMODE)
  4829.         {   draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4830.             worm[player].flashed = FALSE;
  4831.         } else
  4832.         {   // assert(worm[player].mode == TONGUE || worm[player].mode == ARMOUR);
  4833.             if ((worm[player].mode == TONGUE && worm[player].tongue < 10)
  4834.              || (worm[player].mode == ARMOUR && worm[player].armour < 10))
  4835.             {   if (!worm[player].flashed)
  4836.                     draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4837.                 else draw(worm[player].x, worm[player].y, WHITENED);
  4838.                 worm[player].flashed = !worm[player].flashed;
  4839.             } else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4840.     }   }
  4841.     else draw(worm[player].x, worm[player].y, SKULL);
  4842. }
  4843.  
  4844. AGLOBAL void drawsquare(SBYTE x, SBYTE y)
  4845. {    UBYTE which;
  4846.  
  4847.     if (field[x][y] == DOG)
  4848.     {    which = whichcreature(x, y, DOG, 255);
  4849.         if (!creature[which].dormant)
  4850.             draw(x, y, DOGDORMANT);
  4851.         elif (creature[which].dormant <= CHASING)
  4852.             draw(x, y, DOGAWAKENING);
  4853.         else draw(x, y, DOG);
  4854.     } elif (field[x][y] >= FIRSTHEAD && field[x][y] <= LASTHEAD)
  4855.         drawhead(field[x][y] - FIRSTHEAD, x, y);
  4856.     else draw(x, y, field[x][y]);
  4857. }
  4858.  
  4859. MODULE void updatearrow(SBYTE arrowy)
  4860. {   SBYTE i, var = -1;
  4861.  
  4862.     /* var of:
  4863.                   -2         : many there
  4864.                   -1         : nothing there
  4865.                  0-3         : just that worm,
  4866.        FIRSTLETTER-LASTLETTER: just that letter */
  4867.  
  4868.     for (i = 0; i <= 3; i++)
  4869.         if (worm[i].control != NONE && worm[i].y == arrowy && (worm[i].lives || field[worm[i].x][worm[i].y] == SKULL))
  4870.             if (var == -1)
  4871.                 var = i;
  4872.             else var = -2;
  4873.     if (lettery == arrowy)
  4874.         if (var == -1)
  4875.             var = lettertype;
  4876.         else var = -2;
  4877.     if (var == -2)
  4878.         draw(ARROWX, arrowy, ALL);
  4879.     elif (var == -1)
  4880.         draw(ARROWX, arrowy, BLACKENED);
  4881.     elif (var >= FIRSTLETTER && var <= LASTLETTER)
  4882.         draw(ARROWX, arrowy, var);
  4883.     else
  4884.     {   // assert(var >= 0 && var <= 3);
  4885.         if (worm[var].lives)
  4886.             draw(ARROWX, arrowy, FIRSTARROW + var);
  4887.         else draw(ARROWX, arrowy, SKULL);
  4888. }   }
  4889.  
  4890. MODULE void __inline bangdynamite(SBYTE x, SBYTE y, SBYTE player)
  4891. {   SBYTE xx, yy;
  4892.  
  4893.     // Infects (turns to bang-dynamite) all surrounding dynamite.
  4894.  
  4895.     for (xx = x - 1; xx <= x + 1; xx++)
  4896.         for (yy = y - 1; yy <= y + 1; yy++)
  4897.             if (valid(xx, yy))
  4898.                 if (field[xx][yy] == DYNAMITE)
  4899.                 {   field[xx][yy] = TEMPBANGDYNAMITE;
  4900.                     worm[player].dynamitescore += DYNAMITEPOINT;
  4901.                     infector[xx][yy] = player;
  4902.                 }
  4903. }
  4904.  
  4905. MODULE void octopusfire(UBYTE which)
  4906. {   UBYTE i;
  4907.     SBYTE x, y;
  4908.  
  4909.     for (i = 0; i <= CREATURES; i++)
  4910.     {   if (!creature[i].alive)
  4911.         {   switch(creature[which].dir)
  4912.             {
  4913.             case 0:
  4914.                 creature[i].deltax = 0;
  4915.                 creature[i].deltay = -1;
  4916.             break;
  4917.             case 1:
  4918.                 creature[i].deltax = 1;
  4919.                 creature[i].deltay = -1;
  4920.             break;
  4921.             case 2:
  4922.                 creature[i].deltax = 1;
  4923.                 creature[i].deltay = 0;
  4924.             break;
  4925.             case 3:
  4926.                 creature[i].deltax = 1;
  4927.                 creature[i].deltay = 1;
  4928.             break;
  4929.             case 4:
  4930.                 creature[i].deltax = 0;
  4931.                 creature[i].deltay = 1;
  4932.             break;
  4933.             case 5:
  4934.                 creature[i].deltax = -1;
  4935.                 creature[i].deltay = 1;
  4936.             break;
  4937.             case 6:
  4938.                 creature[i].deltax = -1;
  4939.                 creature[i].deltay = 0;
  4940.             break;
  4941.             case 7:
  4942.                 creature[i].deltax = -1;
  4943.                 creature[i].deltay = -1;
  4944.             break;
  4945.             default:
  4946.             break;
  4947.             }
  4948.             x = creature[which].x + creature[i].deltax;
  4949.             y = creature[which].y + creature[i].deltay;
  4950.             if (valid(x, y) && field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
  4951.             {   effect(FXGET_PULSE);
  4952.                 creature[i].last = EMPTY;
  4953.                 creature[i].visible = TRUE;
  4954.                 creature[i].x = x;
  4955.                 creature[i].y = y;
  4956.                 creature[i].speed = octopusspeed;
  4957.                 creature[i].species = FRAGMENT;
  4958.                 creature[i].alive = TRUE;
  4959.                 change(x, y, FRAGMENT);
  4960.                 goto out;
  4961.     }   }   }
  4962.  
  4963. out:
  4964.     if (++creature[which].dir == 8)
  4965.     {   creature[which].dir = -1;
  4966. }   }
  4967.  
  4968.